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

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

Issue 22920004: Reimplement MoveOperation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 4 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 (c) 2012 The Chromium Authors. All rights reserved. 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 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/move_operation.h" 5 #include "chrome/browser/chromeos/drive/file_system/move_operation.h"
6 6
7 #include "chrome/browser/chromeos/drive/drive.pb.h" 7 #include "chrome/browser/chromeos/drive/drive.pb.h"
8 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h" 8 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
9 #include "chrome/browser/chromeos/drive/file_system_util.h" 9 #include "chrome/browser/chromeos/drive/file_system_util.h"
10 #include "chrome/browser/chromeos/drive/job_scheduler.h" 10 #include "chrome/browser/chromeos/drive/job_scheduler.h"
11 #include "content/public/browser/browser_thread.h" 11 #include "content/public/browser/browser_thread.h"
12 12
13 using content::BrowserThread; 13 using content::BrowserThread;
14 14
15 namespace drive { 15 namespace drive {
16 namespace file_system { 16 namespace file_system {
17 namespace {
17 18
18 MoveOperation::MoveOperation(OperationObserver* observer, 19 // Looks up ResourceEntry for source entry and the destination directory.
20 FileError PrepareMove(internal::ResourceMetadata* metadata,
21 const base::FilePath& src_path,
22 const base::FilePath& dest_parent_path,
23 ResourceEntry* src_entry,
24 ResourceEntry* dest_parent_entry) {
25 DCHECK(metadata);
hashimoto 2013/08/21 07:49:08 nit: Do we need this? At least, two functions belo
hidehiko 2013/08/21 08:07:00 Ok, removed.
26 DCHECK(src_entry);
27 DCHECK(dest_parent_entry);
28
29 FileError error = metadata->GetResourceEntryByPath(src_path, src_entry);
30 if (error != FILE_ERROR_OK)
31 return error;
32
33 return metadata->GetResourceEntryByPath(dest_parent_path, dest_parent_entry);
34 }
35
36 // Applies renaming to the local metadata.
37 FileError RenameLocally(internal::ResourceMetadata* metadata,
38 const std::string& resource_id,
39 const std::string& new_title) {
40 ResourceEntry entry;
41 FileError error = metadata->GetResourceEntryById(resource_id, &entry);
42 if (error != FILE_ERROR_OK)
43 return error;
44
45 entry.set_title(new_title);
46 return metadata->RefreshEntry(entry);
47 }
48
49 // Applies directory-moving to the local metadata.
50 FileError MoveDirectoryLocally(internal::ResourceMetadata* metadata,
51 const std::string& resource_id,
52 const std::string& parent_resource_id) {
53 ResourceEntry entry;
54 FileError error = metadata->GetResourceEntryById(resource_id, &entry);
55 if (error != FILE_ERROR_OK)
56 return error;
57
58 // Make sure that the parent exists and it is actually a directory.
hashimoto 2013/08/21 07:49:08 ResourceMetadata::RefreshEntry does this check.
hidehiko 2013/08/21 08:07:00 Removed. Instead, edit ResourceMetadata::RefreshEn
59 ResourceEntry parent_entry;
60 error = metadata->GetResourceEntryById(parent_resource_id, &parent_entry);
61 if (error != FILE_ERROR_OK)
62 return error;
63
64 if (!parent_entry.file_info().is_directory())
65 return FILE_ERROR_NOT_A_DIRECTORY;
66
67 // Update the parent.
68 entry.set_parent_resource_id(parent_resource_id);
69 return metadata->RefreshEntry(entry);
70 }
71
72 } // namespace
73
74 MoveOperation::MoveOperation(base::SequencedTaskRunner* blocking_task_runner,
75 OperationObserver* observer,
19 JobScheduler* scheduler, 76 JobScheduler* scheduler,
20 internal::ResourceMetadata* metadata) 77 internal::ResourceMetadata* metadata)
21 : observer_(observer), 78 : blocking_task_runner_(blocking_task_runner),
22 scheduler_(scheduler), 79 observer_(observer),
23 metadata_(metadata), 80 scheduler_(scheduler),
24 weak_ptr_factory_(this) { 81 metadata_(metadata),
82 weak_ptr_factory_(this) {
25 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
26 } 84 }
27 85
28 MoveOperation::~MoveOperation() { 86 MoveOperation::~MoveOperation() {
29 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
30 } 88 }
31 89
32 void MoveOperation::Move(const base::FilePath& src_file_path, 90 void MoveOperation::Move(const base::FilePath& src_file_path,
33 const base::FilePath& dest_file_path, 91 const base::FilePath& dest_file_path,
34 const FileOperationCallback& callback) { 92 const FileOperationCallback& callback) {
35 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
36 DCHECK(!callback.is_null()); 94 DCHECK(!callback.is_null());
37 95
38 metadata_->GetResourceEntryPairByPathsOnUIThread( 96 scoped_ptr<ResourceEntry> src_entry(new ResourceEntry);
39 src_file_path, 97 scoped_ptr<ResourceEntry> dest_parent_entry(new ResourceEntry);
40 dest_file_path.DirName(), 98 ResourceEntry* src_entry_ptr = src_entry.get();
41 base::Bind(&MoveOperation::MoveAfterGetResourceEntryPair, 99 ResourceEntry* dest_parent_entry_ptr = dest_parent_entry.get();
100 base::PostTaskAndReplyWithResult(
101 blocking_task_runner_.get(),
102 FROM_HERE,
103 base::Bind(&PrepareMove,
104 metadata_, src_file_path, dest_file_path.DirName(),
105 src_entry_ptr, dest_parent_entry_ptr),
106 base::Bind(&MoveOperation::MoveAfterPrepare,
42 weak_ptr_factory_.GetWeakPtr(), 107 weak_ptr_factory_.GetWeakPtr(),
43 dest_file_path, 108 src_file_path, dest_file_path, callback,
44 callback)); 109 base::Passed(&src_entry),
110 base::Passed(&dest_parent_entry)));
45 } 111 }
46 112
47 void MoveOperation::MoveAfterGetResourceEntryPair( 113 void MoveOperation::MoveAfterPrepare(
114 const base::FilePath& src_file_path,
48 const base::FilePath& dest_file_path, 115 const base::FilePath& dest_file_path,
49 const FileOperationCallback& callback, 116 const FileOperationCallback& callback,
50 scoped_ptr<EntryInfoPairResult> src_dest_info) { 117 scoped_ptr<ResourceEntry> src_entry,
118 scoped_ptr<ResourceEntry> dest_parent_entry,
119 FileError error) {
51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 120 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
52 DCHECK(!callback.is_null()); 121 DCHECK(!callback.is_null());
53 DCHECK(src_dest_info.get());
54
55 if (src_dest_info->first.error != FILE_ERROR_OK) {
56 callback.Run(src_dest_info->first.error);
57 return;
58 }
59 if (src_dest_info->second.error != FILE_ERROR_OK) {
60 callback.Run(src_dest_info->second.error);
61 return;
62 }
63 if (!src_dest_info->second.entry->file_info().is_directory()) {
64 callback.Run(FILE_ERROR_NOT_A_DIRECTORY);
65 return;
66 }
67
68 const std::string& src_id = src_dest_info->first.entry->resource_id();
69 const base::FilePath& src_path = src_dest_info->first.path;
70 const base::FilePath new_name = dest_file_path.BaseName();
71 const bool new_name_has_hosted_extension =
72 src_dest_info->first.entry->has_file_specific_info() &&
73 src_dest_info->first.entry->file_specific_info().is_hosted_document() &&
74 new_name.Extension() ==
75 src_dest_info->first.entry->file_specific_info().document_extension();
76
77 Rename(src_id, src_path, new_name, new_name_has_hosted_extension,
78 base::Bind(&MoveOperation::MoveAfterRename,
79 weak_ptr_factory_.GetWeakPtr(),
80 callback,
81 base::Passed(&src_dest_info)));
82 }
83
84 void MoveOperation::MoveAfterRename(
85 const FileOperationCallback& callback,
86 scoped_ptr<EntryInfoPairResult> src_dest_info,
87 FileError error,
88 const base::FilePath& src_path) {
89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
90 122
91 if (error != FILE_ERROR_OK) { 123 if (error != FILE_ERROR_OK) {
92 callback.Run(error); 124 callback.Run(error);
93 return; 125 return;
94 } 126 }
95 127
96 const std::string& src_id = src_dest_info->first.entry->resource_id(); 128 if (!dest_parent_entry->file_info().is_directory()) {
97 const std::string& dest_dir_id = src_dest_info->second.entry->resource_id(); 129 // The parent of the destination is not a directory.
98 const base::FilePath& dest_dir_path = src_dest_info->second.path; 130 callback.Run(FILE_ERROR_NOT_A_DIRECTORY);
99
100 // The source and the destination directory are the same. Nothing more to do.
101 if (src_path.DirName() == dest_dir_path) {
102 observer_->OnDirectoryChangedByOperation(dest_dir_path);
103 callback.Run(FILE_ERROR_OK);
104 return; 131 return;
105 } 132 }
106 133
107 AddToDirectory(src_id, dest_dir_id, src_path, dest_dir_path, 134 // Strip the extension for a hosted document if necessary.
108 base::Bind(&MoveOperation::MoveAfterAddToDirectory, 135 const bool has_hosted_document_extension =
109 weak_ptr_factory_.GetWeakPtr(), 136 src_entry->has_file_specific_info() &&
110 callback, 137 src_entry->file_specific_info().is_hosted_document() &&
111 base::Passed(&src_dest_info))); 138 dest_file_path.Extension() ==
139 src_entry->file_specific_info().document_extension();
140 const std::string new_title =
141 has_hosted_document_extension ?
142 dest_file_path.BaseName().RemoveExtension().AsUTF8Unsafe() :
143 dest_file_path.BaseName().AsUTF8Unsafe();
144
145 // TODO(hidehiko): On Drive API v2, we can move a resource by only one
146 // server request. Implement here. crbug.com/241814
147
148 ResourceEntry* src_entry_ptr = src_entry.get();
149 Rename(*src_entry_ptr, new_title,
150 base::Bind(&MoveOperation::MoveAfterRename,
151 weak_ptr_factory_.GetWeakPtr(),
152 src_file_path, dest_file_path, callback,
153 base::Passed(&src_entry),
154 base::Passed(&dest_parent_entry)));
112 } 155 }
113 156
114 void MoveOperation::MoveAfterAddToDirectory( 157 void MoveOperation::MoveAfterRename(
158 const base::FilePath& src_file_path,
159 const base::FilePath& dest_file_path,
115 const FileOperationCallback& callback, 160 const FileOperationCallback& callback,
116 scoped_ptr<EntryInfoPairResult> src_dest_info, 161 scoped_ptr<ResourceEntry> src_entry,
117 FileError error, 162 scoped_ptr<ResourceEntry> dest_parent_entry,
118 const base::FilePath& new_path) { 163 FileError error) {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
165 DCHECK(!callback.is_null());
120 166
121 if (error != FILE_ERROR_OK) { 167 if (error != FILE_ERROR_OK) {
122 callback.Run(error); 168 callback.Run(error);
123 return; 169 return;
124 } 170 }
125 171
126 const base::FilePath& src_path = src_dest_info->first.path; 172 // The source and the destination directory are the same. Nothing more to do.
127 observer_->OnDirectoryChangedByOperation(src_path.DirName()); 173 if (src_entry->parent_resource_id() == dest_parent_entry->resource_id()) {
128 observer_->OnDirectoryChangedByOperation(new_path.DirName()); 174 observer_->OnDirectoryChangedByOperation(dest_file_path.DirName());
129 175 callback.Run(FILE_ERROR_OK);
130 RemoveFromDirectory(src_dest_info->first.entry->resource_id(),
131 src_dest_info->first.entry->parent_resource_id(),
132 callback);
133 }
134
135 void MoveOperation::Rename(const std::string& src_id,
136 const base::FilePath& src_path,
137 const base::FilePath& new_name,
138 bool new_name_has_hosted_extension,
139 const FileMoveCallback& callback) {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
141
142 // It is a no-op if the file is renamed to the same name.
143 if (src_path.BaseName() == new_name) {
144 callback.Run(FILE_ERROR_OK, src_path);
145 return; 176 return;
146 } 177 }
147 178
148 // Drop the .g<something> extension from |new_name| if the file being 179 AddToDirectory(src_entry->resource_id(),
149 // renamed is a hosted document and |new_name| has the same .g<something> 180 dest_parent_entry->resource_id(),
150 // extension as the file. 181 base::Bind(&MoveOperation::MoveAfterAddToDirectory,
151 const std::string new_title = new_name_has_hosted_extension ? 182 weak_ptr_factory_.GetWeakPtr(),
152 new_name.RemoveExtension().AsUTF8Unsafe() : 183 src_file_path, dest_file_path, callback,
153 new_name.AsUTF8Unsafe(); 184 src_entry->resource_id(),
154 185 src_entry->parent_resource_id()));
155 // Rename on the server.
156 scheduler_->RenameResource(src_id,
157 new_title,
158 base::Bind(&MoveOperation::RenameLocally,
159 weak_ptr_factory_.GetWeakPtr(),
160 src_path,
161 new_title,
162 callback));
163 } 186 }
164 187
165 void MoveOperation::RenameLocally(const base::FilePath& src_path, 188 void MoveOperation::MoveAfterAddToDirectory(
166 const std::string& new_title, 189 const base::FilePath& src_file_path,
167 const FileMoveCallback& callback, 190 const base::FilePath& dest_file_path,
168 google_apis::GDataErrorCode status) { 191 const FileOperationCallback& callback,
192 const std::string& resource_id,
193 const std::string& parent_resource_id,
194 FileError error) {
169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
196 DCHECK(!callback.is_null());
197
198 if (error != FILE_ERROR_OK) {
199 callback.Run(error);
200 return;
201 }
202
203 // Notify to the observers.
204 observer_->OnDirectoryChangedByOperation(src_file_path.DirName());
205 observer_->OnDirectoryChangedByOperation(dest_file_path.DirName());
206
207 RemoveFromDirectory(resource_id, parent_resource_id, callback);
208 }
209
210 void MoveOperation::Rename(const ResourceEntry& entry,
211 const std::string& new_title,
212 const FileOperationCallback& callback) {
213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
214 DCHECK(!callback.is_null());
215
216 if (entry.title() == new_title) {
217 // We have nothing to do.
218 callback.Run(FILE_ERROR_OK);
219 return;
220 }
221
222 // Send a rename request to the server.
223 scheduler_->RenameResource(
224 entry.resource_id(),
225 new_title,
226 base::Bind(&MoveOperation::RenameAfterRenameResource,
227 weak_ptr_factory_.GetWeakPtr(),
228 entry.resource_id(), new_title, callback));
229 }
230
231 void MoveOperation::RenameAfterRenameResource(
232 const std::string& resource_id,
233 const std::string& new_title,
234 const FileOperationCallback& callback,
235 google_apis::GDataErrorCode status) {
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
237 DCHECK(!callback.is_null());
170 238
171 const FileError error = GDataToFileError(status); 239 const FileError error = GDataToFileError(status);
172 if (error != FILE_ERROR_OK) { 240 if (error != FILE_ERROR_OK) {
173 callback.Run(error, base::FilePath()); 241 callback.Run(error);
174 return; 242 return;
175 } 243 }
176 metadata_->RenameEntryOnUIThread(src_path, new_title, callback); 244
245 // Server side renaming is done. Update the local metadata.
246 base::PostTaskAndReplyWithResult(
247 blocking_task_runner_.get(),
248 FROM_HERE,
249 base::Bind(&RenameLocally, metadata_, resource_id, new_title),
250 callback);
177 } 251 }
178 252
179 void MoveOperation::AddToDirectory(const std::string& src_id, 253 void MoveOperation::AddToDirectory(
180 const std::string& dest_dir_id, 254 const std::string& resource_id,
181 const base::FilePath& src_path, 255 const std::string& parent_resource_id,
182 const base::FilePath& dest_dir_path, 256 const FileOperationCallback& callback) {
183 const FileMoveCallback& callback) {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
258 DCHECK(!callback.is_null());
185 259
186 scheduler_->AddResourceToDirectory( 260 scheduler_->AddResourceToDirectory(
187 dest_dir_id, src_id, 261 parent_resource_id, resource_id,
188 base::Bind(&MoveOperation::AddToDirectoryLocally, 262 base::Bind(&MoveOperation::AddToDirectoryAfterAddResourceToDirectory,
189 weak_ptr_factory_.GetWeakPtr(), 263 weak_ptr_factory_.GetWeakPtr(),
190 src_path, 264 resource_id, parent_resource_id, callback));
191 dest_dir_path,
192 callback));
193 } 265 }
194 266
195 void MoveOperation::AddToDirectoryLocally(const base::FilePath& src_path, 267 void MoveOperation::AddToDirectoryAfterAddResourceToDirectory(
196 const base::FilePath& dest_dir_path, 268 const std::string& resource_id,
197 const FileMoveCallback& callback, 269 const std::string& parent_resource_id,
198 google_apis::GDataErrorCode status) { 270 const FileOperationCallback& callback,
271 google_apis::GDataErrorCode status) {
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
273 DCHECK(!callback.is_null());
200 274
201 const FileError error = GDataToFileError(status); 275 const FileError error = GDataToFileError(status);
202 if (error != FILE_ERROR_OK) { 276 if (error != FILE_ERROR_OK) {
203 callback.Run(error, base::FilePath()); 277 callback.Run(error);
204 return; 278 return;
205 } 279 }
206 metadata_->MoveEntryToDirectoryOnUIThread(src_path, dest_dir_path, callback); 280
281 // Server side moving is done. Update the local metadata.
282 base::PostTaskAndReplyWithResult(
283 blocking_task_runner_.get(),
284 FROM_HERE,
285 base::Bind(&MoveDirectoryLocally,
286 metadata_, resource_id, parent_resource_id),
287 callback);
207 } 288 }
208 289
209 void MoveOperation::RemoveFromDirectory( 290 void MoveOperation::RemoveFromDirectory(
210 const std::string& resource_id, 291 const std::string& resource_id,
211 const std::string& directory_resource_id, 292 const std::string& directory_resource_id,
212 const FileOperationCallback& callback) { 293 const FileOperationCallback& callback) {
213 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
295 DCHECK(!callback.is_null());
214 296
215 // Moving files out from "drive/other" special folder for storing orphan files 297 // Moving files out from "drive/other" special folder for storing orphan files
216 // has no meaning in the server. Just skip the step. 298 // has no meaning in the server. Just skip the step.
217 if (util::IsSpecialResourceId(directory_resource_id)) { 299 if (util::IsSpecialResourceId(directory_resource_id)) {
218 callback.Run(FILE_ERROR_OK); 300 callback.Run(FILE_ERROR_OK);
219 return; 301 return;
220 } 302 }
221 303
222 scheduler_->RemoveResourceFromDirectory( 304 scheduler_->RemoveResourceFromDirectory(
223 directory_resource_id, 305 directory_resource_id,
224 resource_id, 306 resource_id,
225 base::Bind(&MoveOperation::RemoveFromDirectoryCompleted, 307 base::Bind(
226 weak_ptr_factory_.GetWeakPtr(), 308 &MoveOperation::RemoveFromDirectoryAfterRemoveResourceFromDirectory,
227 callback)); 309 weak_ptr_factory_.GetWeakPtr(), callback));
228 } 310 }
229 311
230 void MoveOperation::RemoveFromDirectoryCompleted( 312 void MoveOperation::RemoveFromDirectoryAfterRemoveResourceFromDirectory(
231 const FileOperationCallback& callback, 313 const FileOperationCallback& callback,
232 google_apis::GDataErrorCode status) { 314 google_apis::GDataErrorCode status) {
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
316 DCHECK(!callback.is_null());
234 callback.Run(GDataToFileError(status)); 317 callback.Run(GDataToFileError(status));
235 } 318 }
236 319
237 } // namespace file_system 320 } // namespace file_system
238 } // namespace drive 321 } // namespace drive
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698