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

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

Powered by Google App Engine
This is Rietveld 408576698