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

Side by Side Diff: chrome/browser/chromeos/drive/drive_resource_metadata.cc

Issue 12465012: chromeos: Change DriveResourceMetadata's method arguemnts from DriveEntryProto* to resource ID when… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments Created 7 years, 9 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/drive_resource_metadata.h" 5 #include "chrome/browser/chromeos/drive/drive_resource_metadata.h"
6 6
7 #include <leveldb/db.h> 7 #include <leveldb/db.h>
8 #include <stack> 8 #include <stack>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
108 void DriveResourceMetadata::ClearRoot() { 108 void DriveResourceMetadata::ClearRoot() {
109 if (!root_.get()) 109 if (!root_.get())
110 return; 110 return;
111 111
112 // The root is not yet initialized. 112 // The root is not yet initialized.
113 if (root_->resource_id().empty()) 113 if (root_->resource_id().empty())
114 return; 114 return;
115 115
116 // Note that children have a reference to root_, 116 // Note that children have a reference to root_,
117 // so we need to delete them here. 117 // so we need to delete them here.
118 RemoveDirectoryChildren(root_.get()); 118 RemoveDirectoryChildren(root_->resource_id());
119 RemoveEntryFromResourceMap(root_->resource_id()); 119 RemoveEntryFromResourceMap(root_->resource_id());
120 DCHECK(resource_map_.empty()); 120 DCHECK(resource_map_.empty());
121 // The resource_map_ should be empty here, but to make sure for non-Debug 121 // The resource_map_ should be empty here, but to make sure for non-Debug
122 // build. 122 // build.
123 resource_map_.clear(); 123 resource_map_.clear();
124 root_.reset(); 124 root_.reset();
125 } 125 }
126 126
127 void DriveResourceMetadata::GetLargestChangestamp( 127 void DriveResourceMetadata::GetLargestChangestamp(
128 const GetChangestampCallback& callback) { 128 const GetChangestampCallback& callback) {
(...skipping 17 matching lines...) Expand all
146 DCHECK(!directory_path.empty()); 146 DCHECK(!directory_path.empty());
147 DCHECK(!file_path.empty()); 147 DCHECK(!file_path.empty());
148 DCHECK(!callback.is_null()); 148 DCHECK(!callback.is_null());
149 149
150 DriveEntryProto* entry = FindEntryByPathSync(file_path); 150 DriveEntryProto* entry = FindEntryByPathSync(file_path);
151 if (!entry) { 151 if (!entry) {
152 PostFileMoveCallbackError(callback, DRIVE_FILE_ERROR_NOT_FOUND); 152 PostFileMoveCallbackError(callback, DRIVE_FILE_ERROR_NOT_FOUND);
153 return; 153 return;
154 } 154 }
155 155
156 // Cannot move an entry without its parent. (i.e. the root)
157 if (entry->parent_resource_id().empty()) {
158 PostFileMoveCallbackError(callback, DRIVE_FILE_ERROR_INVALID_OPERATION);
159 return;
160 }
161
156 DriveEntryProto* destination = FindEntryByPathSync(directory_path); 162 DriveEntryProto* destination = FindEntryByPathSync(directory_path);
157 base::FilePath moved_file_path; 163 base::FilePath moved_file_path;
158 DriveFileError error = DRIVE_FILE_ERROR_FAILED; 164 DriveFileError error = DRIVE_FILE_ERROR_FAILED;
159 if (!destination) { 165 if (!destination) {
160 error = DRIVE_FILE_ERROR_NOT_FOUND; 166 error = DRIVE_FILE_ERROR_NOT_FOUND;
161 } else if (!destination->file_info().is_directory()) { 167 } else if (!destination->file_info().is_directory()) {
162 error = DRIVE_FILE_ERROR_NOT_A_DIRECTORY; 168 error = DRIVE_FILE_ERROR_NOT_A_DIRECTORY;
163 } else { 169 } else {
164 DriveEntryProto* parent = entry->parent_resource_id().empty() ? NULL : 170 DetachEntryFromDirectory(entry->resource_id());
165 GetEntryByResourceId(entry->parent_resource_id()); 171 entry->set_parent_resource_id(destination->resource_id());
166 if (parent && parent->file_info().is_directory()) 172 AddEntryToDirectory(entry);
167 DetachEntryFromDirectory(parent, entry); 173 moved_file_path = GetFilePath(entry->resource_id());
168
169 AddEntryToDirectory(destination, entry);
170 moved_file_path = GetFilePath(*entry);
171 error = DRIVE_FILE_OK; 174 error = DRIVE_FILE_OK;
172 } 175 }
173 DVLOG(1) << "MoveEntryToDirectory " << moved_file_path.value(); 176 DVLOG(1) << "MoveEntryToDirectory " << moved_file_path.value();
174 base::MessageLoopProxy::current()->PostTask( 177 base::MessageLoopProxy::current()->PostTask(
175 FROM_HERE, base::Bind(callback, error, moved_file_path)); 178 FROM_HERE, base::Bind(callback, error, moved_file_path));
176 } 179 }
177 180
178 void DriveResourceMetadata::RenameEntry( 181 void DriveResourceMetadata::RenameEntry(
179 const base::FilePath& file_path, 182 const base::FilePath& file_path,
180 const base::FilePath::StringType& new_name, 183 const base::FilePath::StringType& new_name,
181 const FileMoveCallback& callback) { 184 const FileMoveCallback& callback) {
182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
183 DCHECK(!file_path.empty()); 186 DCHECK(!file_path.empty());
184 DCHECK(!new_name.empty()); 187 DCHECK(!new_name.empty());
185 DCHECK(!callback.is_null()); 188 DCHECK(!callback.is_null());
186 189
187 DVLOG(1) << "RenameEntry " << file_path.value() << " to " << new_name; 190 DVLOG(1) << "RenameEntry " << file_path.value() << " to " << new_name;
188 DriveEntryProto* entry = FindEntryByPathSync(file_path); 191 DriveEntryProto* entry = FindEntryByPathSync(file_path);
189 if (!entry) { 192 if (!entry) {
190 PostFileMoveCallbackError(callback, DRIVE_FILE_ERROR_NOT_FOUND); 193 PostFileMoveCallbackError(callback, DRIVE_FILE_ERROR_NOT_FOUND);
191 return; 194 return;
192 } 195 }
193 196
194 if (new_name == file_path.BaseName().value()) { 197 if (new_name == file_path.BaseName().value()) {
195 PostFileMoveCallbackError(callback, DRIVE_FILE_ERROR_EXISTS); 198 PostFileMoveCallbackError(callback, DRIVE_FILE_ERROR_EXISTS);
196 return; 199 return;
197 } 200 }
198 201
199 entry->set_title(new_name); 202 entry->set_title(new_name);
200
201 DriveEntryProto* parent = GetEntryByResourceId(entry->parent_resource_id());
202 DCHECK(parent);
203 // After changing the title of the entry, call MoveEntryToDirectory to 203 // After changing the title of the entry, call MoveEntryToDirectory to
204 // remove the entry from its parent directory and then add it back in order to 204 // remove the entry from its parent directory and then add it back in order to
205 // go through the file name de-duplication. 205 // go through the file name de-duplication.
206 // TODO(achuith/satorux/zel): This code is fragile. The title has been 206 // TODO(achuith/satorux/zel): This code is fragile. The title has been
207 // changed, but not the file_name. MoveEntryToDirectory calls RemoveChild to 207 // changed, but not the file_name. MoveEntryToDirectory calls RemoveChild to
208 // remove the child based on the old file_name, and then re-adds the child by 208 // remove the child based on the old file_name, and then re-adds the child by
209 // first assigning the new title to file_name. http://crbug.com/30157 209 // first assigning the new title to file_name. http://crbug.com/30157
210 MoveEntryToDirectory(file_path, GetFilePath(*parent), callback); 210 MoveEntryToDirectory(file_path,
211 GetFilePath(entry->parent_resource_id()), callback);
211 } 212 }
212 213
213 void DriveResourceMetadata::RemoveEntry(const std::string& resource_id, 214 void DriveResourceMetadata::RemoveEntry(const std::string& resource_id,
214 const FileMoveCallback& callback) { 215 const FileMoveCallback& callback) {
215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
216 DCHECK(!callback.is_null()); 217 DCHECK(!callback.is_null());
217 218
218 // Disallow deletion of root. 219 // Disallow deletion of root.
219 if (resource_id == root_->resource_id()) { 220 if (resource_id == root_->resource_id()) {
220 PostFileMoveCallbackError(callback, DRIVE_FILE_ERROR_ACCESS_DENIED); 221 PostFileMoveCallbackError(callback, DRIVE_FILE_ERROR_ACCESS_DENIED);
221 return; 222 return;
222 } 223 }
223 224
224 DriveEntryProto* entry = GetEntryByResourceId(resource_id); 225 DriveEntryProto* entry = GetEntryByResourceId(resource_id);
225 if (!entry) { 226 if (!entry) {
226 PostFileMoveCallbackError(callback, DRIVE_FILE_ERROR_NOT_FOUND); 227 PostFileMoveCallbackError(callback, DRIVE_FILE_ERROR_NOT_FOUND);
227 return; 228 return;
228 } 229 }
229 230
230 DriveEntryProto* parent = GetEntryByResourceId(entry->parent_resource_id()); 231 const base::FilePath parent_file_path =
231 DCHECK(parent && parent->file_info().is_directory()); 232 GetFilePath(entry->parent_resource_id());
232 233 RemoveDirectoryChild(entry->resource_id());
233 RemoveDirectoryChild(parent, entry);
234 base::MessageLoopProxy::current()->PostTask( 234 base::MessageLoopProxy::current()->PostTask(
235 FROM_HERE, 235 FROM_HERE,
236 base::Bind(callback, DRIVE_FILE_OK, GetFilePath(*parent))); 236 base::Bind(callback, DRIVE_FILE_OK, parent_file_path));
237 } 237 }
238 238
239 bool DriveResourceMetadata::AddEntryToResourceMap(DriveEntryProto* entry) { 239 bool DriveResourceMetadata::AddEntryToResourceMap(DriveEntryProto* entry) {
240 DVLOG(1) << "AddEntryToResourceMap " << entry->resource_id(); 240 DVLOG(1) << "AddEntryToResourceMap " << entry->resource_id();
241 DCHECK(!entry->resource_id().empty()); 241 DCHECK(!entry->resource_id().empty());
242 std::pair<ResourceMap::iterator, bool> ret = 242 std::pair<ResourceMap::iterator, bool> ret =
243 resource_map_.insert(std::make_pair(entry->resource_id(), entry)); 243 resource_map_.insert(std::make_pair(entry->resource_id(), entry));
244 DCHECK(ret.second); // resource_id did not previously exist in the map. 244 DCHECK(ret.second); // resource_id did not previously exist in the map.
245 return ret.second; 245 return ret.second;
246 } 246 }
247 247
248 void DriveResourceMetadata::RemoveEntryFromResourceMap( 248 void DriveResourceMetadata::RemoveEntryFromResourceMap(
249 const std::string& resource_id) { 249 const std::string& resource_id) {
250 DVLOG(1) << "RemoveEntryFromResourceMap " << resource_id; 250 DVLOG(1) << "RemoveEntryFromResourceMap " << resource_id;
251 DCHECK(!resource_id.empty()); 251 DCHECK(!resource_id.empty());
252 size_t ret = resource_map_.erase(resource_id); 252 size_t ret = resource_map_.erase(resource_id);
253 DCHECK_EQ(1u, ret); // resource_id was found in the map. 253 DCHECK_EQ(1u, ret); // resource_id was found in the map.
254 } 254 }
255 255
256 DriveEntryProto* DriveResourceMetadata::FindEntryByPathSync( 256 DriveEntryProto* DriveResourceMetadata::FindEntryByPathSync(
257 const base::FilePath& file_path) { 257 const base::FilePath& file_path) {
258 if (file_path == GetFilePath(*root_)) 258 if (file_path == GetFilePath(root_->resource_id()))
259 return root_.get(); 259 return root_.get();
260 260
261 std::vector<base::FilePath::StringType> components; 261 std::vector<base::FilePath::StringType> components;
262 file_path.GetComponents(&components); 262 file_path.GetComponents(&components);
263 DriveEntryProto* current_dir = root_.get(); 263 DriveEntryProto* current_dir = root_.get();
264 264
265 for (size_t i = 1; i < components.size() && current_dir; ++i) { 265 for (size_t i = 1; i < components.size() && current_dir; ++i) {
266 std::string resource_id = FindDirectoryChild(current_dir, components[i]); 266 std::string resource_id = FindDirectoryChild(current_dir->resource_id(),
267 components[i]);
267 if (resource_id.empty()) 268 if (resource_id.empty())
268 return NULL; 269 return NULL;
269 270
270 DriveEntryProto* entry = GetEntryByResourceId(resource_id); 271 DriveEntryProto* entry = GetEntryByResourceId(resource_id);
271 DCHECK(entry); 272 DCHECK(entry);
272 273
273 if (i == components.size() - 1) // Last component. 274 if (i == components.size() - 1) // Last component.
274 return entry; 275 return entry;
275 if (!entry->file_info().is_directory()) 276 if (!entry->file_info().is_directory())
276 return NULL; 277 return NULL;
(...skipping 16 matching lines...) Expand all
293 DCHECK(!callback.is_null()); 294 DCHECK(!callback.is_null());
294 295
295 scoped_ptr<DriveEntryProto> entry_proto; 296 scoped_ptr<DriveEntryProto> entry_proto;
296 DriveFileError error = DRIVE_FILE_ERROR_FAILED; 297 DriveFileError error = DRIVE_FILE_ERROR_FAILED;
297 base::FilePath drive_file_path; 298 base::FilePath drive_file_path;
298 299
299 DriveEntryProto* entry = GetEntryByResourceId(resource_id); 300 DriveEntryProto* entry = GetEntryByResourceId(resource_id);
300 if (entry) { 301 if (entry) {
301 entry_proto.reset(new DriveEntryProto(*entry)); 302 entry_proto.reset(new DriveEntryProto(*entry));
302 error = DRIVE_FILE_OK; 303 error = DRIVE_FILE_OK;
303 drive_file_path = GetFilePath(*entry); 304 drive_file_path = GetFilePath(entry->resource_id());
304 } else { 305 } else {
305 error = DRIVE_FILE_ERROR_NOT_FOUND; 306 error = DRIVE_FILE_ERROR_NOT_FOUND;
306 } 307 }
307 308
308 base::MessageLoopProxy::current()->PostTask( 309 base::MessageLoopProxy::current()->PostTask(
309 FROM_HERE, 310 FROM_HERE,
310 base::Bind(callback, error, drive_file_path, base::Passed(&entry_proto))); 311 base::Bind(callback, error, drive_file_path, base::Passed(&entry_proto)));
311 } 312 }
312 313
313 void DriveResourceMetadata::GetEntryInfoByPath( 314 void DriveResourceMetadata::GetEntryInfoByPath(
(...skipping 22 matching lines...) Expand all
336 const base::FilePath& path, 337 const base::FilePath& path,
337 const ReadDirectoryCallback& callback) { 338 const ReadDirectoryCallback& callback) {
338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 339 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
339 DCHECK(!callback.is_null()); 340 DCHECK(!callback.is_null());
340 341
341 scoped_ptr<DriveEntryProtoVector> entries; 342 scoped_ptr<DriveEntryProtoVector> entries;
342 DriveFileError error = DRIVE_FILE_ERROR_FAILED; 343 DriveFileError error = DRIVE_FILE_ERROR_FAILED;
343 344
344 DriveEntryProto* entry = FindEntryByPathSync(path); 345 DriveEntryProto* entry = FindEntryByPathSync(path);
345 if (entry && entry->file_info().is_directory()) { 346 if (entry && entry->file_info().is_directory()) {
346 entries = DirectoryChildrenToProtoVector(entry); 347 entries = DirectoryChildrenToProtoVector(entry->resource_id());
347 error = DRIVE_FILE_OK; 348 error = DRIVE_FILE_OK;
348 } else if (entry && !entry->file_info().is_directory()) { 349 } else if (entry && !entry->file_info().is_directory()) {
349 error = DRIVE_FILE_ERROR_NOT_A_DIRECTORY; 350 error = DRIVE_FILE_ERROR_NOT_A_DIRECTORY;
350 } else { 351 } else {
351 error = DRIVE_FILE_ERROR_NOT_FOUND; 352 error = DRIVE_FILE_ERROR_NOT_FOUND;
352 } 353 }
353 354
354 base::MessageLoopProxy::current()->PostTask( 355 base::MessageLoopProxy::current()->PostTask(
355 FROM_HERE, 356 FROM_HERE,
356 base::Bind(callback, error, base::Passed(&entries))); 357 base::Bind(callback, error, base::Passed(&entries)));
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
389 // Reject incompatible input. 390 // Reject incompatible input.
390 if (entry->file_info().is_directory() != 391 if (entry->file_info().is_directory() !=
391 entry_proto.file_info().is_directory()) { 392 entry_proto.file_info().is_directory()) {
392 PostGetEntryInfoWithFilePathCallbackError( 393 PostGetEntryInfoWithFilePathCallbackError(
393 callback, DRIVE_FILE_ERROR_INVALID_OPERATION); 394 callback, DRIVE_FILE_ERROR_INVALID_OPERATION);
394 return; 395 return;
395 } 396 }
396 397
397 // Update data. 398 // Update data.
398 if (entry != root_.get()) { 399 if (entry != root_.get()) {
399 DriveEntryProto* old_parent = GetDirectory(entry->parent_resource_id());
400 DriveEntryProto* new_parent = 400 DriveEntryProto* new_parent =
401 GetDirectory(entry_proto.parent_resource_id()); 401 GetDirectory(entry_proto.parent_resource_id());
402 402
403 if (!old_parent || !new_parent) { 403 if (!new_parent) {
404 PostGetEntryInfoWithFilePathCallbackError( 404 PostGetEntryInfoWithFilePathCallbackError(
405 callback, DRIVE_FILE_ERROR_NOT_FOUND); 405 callback, DRIVE_FILE_ERROR_NOT_FOUND);
406 return; 406 return;
407 } 407 }
408 408
409 // Remove from the old parent, update the entry, and add it to the new 409 // Remove from the old parent, update the entry, and add it to the new
410 // parent. The order matters here. FromProto() could remove suffix like 410 // parent. The order matters here. FromProto() could remove suffix like
411 // "(2)" from entries with duplicate names. If FromProto() is first 411 // "(2)" from entries with duplicate names. If FromProto() is first
412 // called, RemoveChild() won't work correctly because of the missing 412 // called, RemoveChild() won't work correctly because of the missing
413 // suffix. 413 // suffix.
414 DetachEntryFromDirectory(old_parent, entry); 414 DetachEntryFromDirectory(entry->resource_id());
415 // Note that it's safe to update the directory entry with 415 // Note that it's safe to update the directory entry as it won't clear
416 // DriveEntry::FromProto() as it won't clear children. 416 // children.
417 *entry = CreateEntryWithProperBaseName(entry_proto); 417 *entry = CreateEntryWithProperBaseName(entry_proto);
418 AddEntryToDirectory(new_parent, entry); // Transfers ownership. 418 AddEntryToDirectory(entry); // Transfers ownership.
419 } else { 419 } else {
420 // root has no parent. 420 // root has no parent.
421 *entry = CreateEntryWithProperBaseName(entry_proto); 421 *entry = CreateEntryWithProperBaseName(entry_proto);
422 } 422 }
423 423
424 DVLOG(1) << "RefreshEntry " << GetFilePath(*entry).value(); 424 DVLOG(1) << "RefreshEntry " << GetFilePath(entry->resource_id()).value();
425 // Note that base_name is not the same for new_entry and entry_proto. 425 // Note that base_name is not the same for new_entry and entry_proto.
426 scoped_ptr<DriveEntryProto> result_entry_proto(new DriveEntryProto(*entry)); 426 scoped_ptr<DriveEntryProto> result_entry_proto(new DriveEntryProto(*entry));
427 base::MessageLoopProxy::current()->PostTask( 427 base::MessageLoopProxy::current()->PostTask(
428 FROM_HERE, 428 FROM_HERE,
429 base::Bind(callback, 429 base::Bind(callback,
430 DRIVE_FILE_OK, 430 DRIVE_FILE_OK,
431 GetFilePath(*entry), 431 GetFilePath(entry->resource_id()),
432 base::Passed(&result_entry_proto))); 432 base::Passed(&result_entry_proto)));
433 } 433 }
434 434
435 void DriveResourceMetadata::RefreshDirectory( 435 void DriveResourceMetadata::RefreshDirectory(
436 const DirectoryFetchInfo& directory_fetch_info, 436 const DirectoryFetchInfo& directory_fetch_info,
437 const DriveEntryProtoMap& entry_proto_map, 437 const DriveEntryProtoMap& entry_proto_map,
438 const FileMoveCallback& callback) { 438 const FileMoveCallback& callback) {
439 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 439 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
440 DCHECK(!callback.is_null()); 440 DCHECK(!callback.is_null());
441 DCHECK(!directory_fetch_info.empty()); 441 DCHECK(!directory_fetch_info.empty());
(...skipping 28 matching lines...) Expand all
470 // crbug.com/193525. 470 // crbug.com/193525.
471 if (entry_proto.parent_resource_id() != 471 if (entry_proto.parent_resource_id() !=
472 directory_fetch_info.resource_id()) { 472 directory_fetch_info.resource_id()) {
473 DVLOG(1) << "Wrong-parent entry rejected: " << entry_proto.resource_id(); 473 DVLOG(1) << "Wrong-parent entry rejected: " << entry_proto.resource_id();
474 continue; 474 continue;
475 } 475 }
476 476
477 DriveEntryProto* existing_entry = 477 DriveEntryProto* existing_entry =
478 GetEntryByResourceId(entry_proto.resource_id()); 478 GetEntryByResourceId(entry_proto.resource_id());
479 if (existing_entry) { 479 if (existing_entry) {
480 DriveEntryProto* old_parent =
481 GetDirectory(existing_entry->parent_resource_id());
482 DCHECK(old_parent && old_parent->file_info().is_directory());
483 // See the comment in RefreshEntry() for why the existing entry is 480 // See the comment in RefreshEntry() for why the existing entry is
484 // updated in this way. 481 // updated in this way.
485 DetachEntryFromDirectory(old_parent, existing_entry); 482 DetachEntryFromDirectory(existing_entry->resource_id());
486 *existing_entry = CreateEntryWithProperBaseName(entry_proto); 483 *existing_entry = CreateEntryWithProperBaseName(entry_proto);
487 AddEntryToDirectory(directory, existing_entry); 484 AddEntryToDirectory(existing_entry);
488 } else { // New entry. 485 } else { // New entry.
489 // A new directory will have changestamp of zero, so the directory will 486 // A new directory will have changestamp of zero, so the directory will
490 // be "fast-fetched". See crbug.com/178348 for details. 487 // be "fast-fetched". See crbug.com/178348 for details.
491 scoped_ptr<DriveEntryProto> new_entry( 488 scoped_ptr<DriveEntryProto> new_entry(
492 new DriveEntryProto(CreateEntryWithProperBaseName(entry_proto))); 489 new DriveEntryProto(CreateEntryWithProperBaseName(entry_proto)));
493 AddEntryToDirectory(directory, new_entry.release()); 490 AddEntryToDirectory(new_entry.release());
494 } 491 }
495 } 492 }
496 493
497 // Go through the existing entries and remove deleted entries. 494 // Go through the existing entries and remove deleted entries.
498 scoped_ptr<DriveEntryProtoVector> entries = 495 scoped_ptr<DriveEntryProtoVector> entries =
499 DirectoryChildrenToProtoVector(directory); 496 DirectoryChildrenToProtoVector(directory->resource_id());
500 for (size_t i = 0; i < entries->size(); ++i) { 497 for (size_t i = 0; i < entries->size(); ++i) {
501 const DriveEntryProto& entry_proto = entries->at(i); 498 const DriveEntryProto& entry_proto = entries->at(i);
502 if (entry_proto_map.count(entry_proto.resource_id()) == 0) { 499 if (entry_proto_map.count(entry_proto.resource_id()) == 0)
503 DriveEntryProto* entry = GetEntryByResourceId(entry_proto.resource_id()); 500 RemoveDirectoryChild(entry_proto.resource_id());
504 RemoveDirectoryChild(directory, entry);
505 }
506 } 501 }
507 502
508 base::MessageLoopProxy::current()->PostTask( 503 base::MessageLoopProxy::current()->PostTask(
509 FROM_HERE, 504 FROM_HERE,
510 base::Bind(callback, DRIVE_FILE_OK, GetFilePath(*directory))); 505 base::Bind(callback, DRIVE_FILE_OK,
506 GetFilePath(directory->resource_id())));
511 } 507 }
512 508
513 void DriveResourceMetadata::AddEntry(const DriveEntryProto& entry_proto, 509 void DriveResourceMetadata::AddEntry(const DriveEntryProto& entry_proto,
514 const FileMoveCallback& callback) { 510 const FileMoveCallback& callback) {
515 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 511 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
516 DCHECK(!callback.is_null()); 512 DCHECK(!callback.is_null());
517 513
518 DriveEntryProto* parent = GetDirectory(entry_proto.parent_resource_id()); 514 DriveEntryProto* parent = GetDirectory(entry_proto.parent_resource_id());
519 if (!parent) { 515 if (!parent) {
520 PostFileMoveCallbackError(callback, DRIVE_FILE_ERROR_NOT_FOUND); 516 PostFileMoveCallbackError(callback, DRIVE_FILE_ERROR_NOT_FOUND);
521 return; 517 return;
522 } 518 }
523 519
524 DriveEntryProto* added_entry = 520 DriveEntryProto* added_entry =
525 new DriveEntryProto(CreateEntryWithProperBaseName(entry_proto)); 521 new DriveEntryProto(CreateEntryWithProperBaseName(entry_proto));
526 AddEntryToDirectory(parent, added_entry); // Transfers ownership. 522 AddEntryToDirectory(added_entry); // Transfers ownership.
527 base::MessageLoopProxy::current()->PostTask( 523 base::MessageLoopProxy::current()->PostTask(
528 FROM_HERE, 524 FROM_HERE,
529 base::Bind(callback, DRIVE_FILE_OK, GetFilePath(*added_entry))); 525 base::Bind(callback, DRIVE_FILE_OK,
526 GetFilePath(added_entry->resource_id())));
530 } 527 }
531 528
532 DriveEntryProto* DriveResourceMetadata::GetDirectory( 529 DriveEntryProto* DriveResourceMetadata::GetDirectory(
533 const std::string& resource_id) { 530 const std::string& resource_id) {
534 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 531 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
535 DCHECK(!resource_id.empty()); 532 DCHECK(!resource_id.empty());
536 533
537 DriveEntryProto* entry = GetEntryByResourceId(resource_id); 534 DriveEntryProto* entry = GetEntryByResourceId(resource_id);
538 return entry && entry->file_info().is_directory() ? entry : NULL; 535 return entry && entry->file_info().is_directory() ? entry : NULL;
539 } 536 }
540 537
541 base::FilePath DriveResourceMetadata::GetFilePath( 538 base::FilePath DriveResourceMetadata::GetFilePath(
542 const DriveEntryProto& entry) { 539 const std::string& resource_id) {
540 DriveEntryProto* entry = GetEntryByResourceId(resource_id);
541 DCHECK(entry);
543 base::FilePath path; 542 base::FilePath path;
544 DriveEntryProto* parent = entry.parent_resource_id().empty() ? NULL : 543 if (!entry->parent_resource_id().empty())
545 GetEntryByResourceId(entry.parent_resource_id()); 544 path = GetFilePath(entry->parent_resource_id());
546 if (parent) 545 path = path.Append(entry->base_name());
547 path = GetFilePath(*parent);
548 path = path.Append(entry.base_name());
549 return path; 546 return path;
550 } 547 }
551 548
552 void DriveResourceMetadata::GetChildDirectories( 549 void DriveResourceMetadata::GetChildDirectories(
553 const std::string& resource_id, 550 const std::string& resource_id,
554 const GetChildDirectoriesCallback& changed_dirs_callback) { 551 const GetChildDirectoriesCallback& changed_dirs_callback) {
555 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 552 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
556 DCHECK(!changed_dirs_callback.is_null()); 553 DCHECK(!changed_dirs_callback.is_null());
557 554
558 std::set<base::FilePath> changed_directories; 555 std::set<base::FilePath> changed_directories;
559 DriveEntryProto* entry = GetEntryByResourceId(resource_id); 556 DriveEntryProto* entry = GetEntryByResourceId(resource_id);
560 DriveEntryProto* directory = 557 DriveEntryProto* directory =
561 entry && entry->file_info().is_directory() ? entry : NULL; 558 entry && entry->file_info().is_directory() ? entry : NULL;
562 if (directory) 559 if (directory)
563 GetDescendantDirectoryPaths(*directory, &changed_directories); 560 GetDescendantDirectoryPaths(directory->resource_id(), &changed_directories);
564 561
565 base::MessageLoopProxy::current()->PostTask( 562 base::MessageLoopProxy::current()->PostTask(
566 FROM_HERE, 563 FROM_HERE,
567 base::Bind(changed_dirs_callback, changed_directories)); 564 base::Bind(changed_dirs_callback, changed_directories));
568 } 565 }
569 566
570 void DriveResourceMetadata::GetDescendantDirectoryPaths( 567 void DriveResourceMetadata::GetDescendantDirectoryPaths(
571 const DriveEntryProto& directory, 568 const std::string& directory_resource_id,
572 std::set<base::FilePath>* child_directories) { 569 std::set<base::FilePath>* child_directories) {
573 DCHECK(directory.file_info().is_directory()); 570 const ChildMap& children = child_maps_[directory_resource_id];
574 const ChildMap& children = child_maps_[directory.resource_id()];
575 for (ChildMap::const_iterator iter = children.begin(); 571 for (ChildMap::const_iterator iter = children.begin();
576 iter != children.end(); ++iter) { 572 iter != children.end(); ++iter) {
577 DriveEntryProto* entry = GetEntryByResourceId(iter->second); 573 DriveEntryProto* entry = GetEntryByResourceId(iter->second);
578 if (entry && entry->file_info().is_directory()) { 574 if (entry && entry->file_info().is_directory()) {
579 child_directories->insert(GetFilePath(*entry)); 575 child_directories->insert(GetFilePath(entry->resource_id()));
580 GetDescendantDirectoryPaths(*entry, child_directories); 576 GetDescendantDirectoryPaths(entry->resource_id(), child_directories);
581 } 577 }
582 } 578 }
583 } 579 }
584 580
585 void DriveResourceMetadata::RemoveAll(const base::Closure& callback) { 581 void DriveResourceMetadata::RemoveAll(const base::Closure& callback) {
586 RemoveDirectoryChildren(root_.get()); 582 RemoveDirectoryChildren(root_->resource_id());
587 base::MessageLoopProxy::current()->PostTask(FROM_HERE, callback); 583 base::MessageLoopProxy::current()->PostTask(FROM_HERE, callback);
588 } 584 }
589 585
590 void DriveResourceMetadata::SerializeToString(std::string* serialized_proto) { 586 void DriveResourceMetadata::SerializeToString(std::string* serialized_proto) {
591 DriveRootDirectoryProto proto; 587 DriveRootDirectoryProto proto;
592 DirectoryToProto(root_.get(), proto.mutable_drive_directory()); 588 DirectoryToProto(root_->resource_id(), proto.mutable_drive_directory());
593 proto.set_largest_changestamp(largest_changestamp_); 589 proto.set_largest_changestamp(largest_changestamp_);
594 proto.set_version(kProtoVersion); 590 proto.set_version(kProtoVersion);
595 591
596 const bool ok = proto.SerializeToString(serialized_proto); 592 const bool ok = proto.SerializeToString(serialized_proto);
597 DCHECK(ok); 593 DCHECK(ok);
598 } 594 }
599 595
600 bool DriveResourceMetadata::ParseFromString( 596 bool DriveResourceMetadata::ParseFromString(
601 const std::string& serialized_proto) { 597 const std::string& serialized_proto) {
602 DriveRootDirectoryProto proto; 598 DriveRootDirectoryProto proto;
603 if (!proto.ParseFromString(serialized_proto)) 599 if (!proto.ParseFromString(serialized_proto))
604 return false; 600 return false;
605 601
606 if (proto.version() != kProtoVersion) { 602 if (proto.version() != kProtoVersion) {
607 LOG(ERROR) << "Incompatible proto detected (incompatible version): " 603 LOG(ERROR) << "Incompatible proto detected (incompatible version): "
608 << proto.version(); 604 << proto.version();
609 return false; 605 return false;
610 } 606 }
611 607
612 // An old proto file might not have per-directory changestamps. Add them if 608 // An old proto file might not have per-directory changestamps. Add them if
613 // needed. 609 // needed.
614 const DriveDirectoryProto& root = proto.drive_directory(); 610 const DriveDirectoryProto& root = proto.drive_directory();
615 if (!root.drive_entry().directory_specific_info().has_changestamp()) { 611 if (!root.drive_entry().directory_specific_info().has_changestamp()) {
616 AddPerDirectoryChangestamps(proto.mutable_drive_directory(), 612 AddPerDirectoryChangestamps(proto.mutable_drive_directory(),
617 proto.largest_changestamp()); 613 proto.largest_changestamp());
618 } 614 }
619 615
620 ProtoToDirectory(proto.drive_directory(), root_.get()); 616 if (proto.drive_directory().drive_entry().resource_id() !=
617 root_->resource_id()) {
618 LOG(ERROR) << "Incompatible proto detected (incompatible root ID): "
619 << proto.drive_directory().drive_entry().resource_id();
620 return false;
621 }
622
623 *root_ = CreateEntryWithProperBaseName(proto.drive_directory().drive_entry());
624 AddDescendantsFromProto(proto.drive_directory());
621 625
622 loaded_ = true; 626 loaded_ = true;
623 largest_changestamp_ = proto.largest_changestamp(); 627 largest_changestamp_ = proto.largest_changestamp();
624 628
625 return true; 629 return true;
626 } 630 }
627 631
628 void DriveResourceMetadata::GetEntryInfoPairByPathsAfterGetFirst( 632 void DriveResourceMetadata::GetEntryInfoPairByPathsAfterGetFirst(
629 const base::FilePath& first_path, 633 const base::FilePath& first_path,
630 const base::FilePath& second_path, 634 const base::FilePath& second_path,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
665 DCHECK(!callback.is_null()); 669 DCHECK(!callback.is_null());
666 DCHECK(result.get()); 670 DCHECK(result.get());
667 671
668 result->second.path = second_path; 672 result->second.path = second_path;
669 result->second.error = error; 673 result->second.error = error;
670 result->second.proto = entry_proto.Pass(); 674 result->second.proto = entry_proto.Pass();
671 675
672 callback.Run(result.Pass()); 676 callback.Run(result.Pass());
673 } 677 }
674 678
675 void DriveResourceMetadata::AddEntryToDirectory(DriveEntryProto* directory, 679 void DriveResourceMetadata::AddEntryToDirectory(DriveEntryProto* entry) {
676 DriveEntryProto* entry) {
677 DCHECK(directory->file_info().is_directory());
678 DCHECK(entry->parent_resource_id().empty() ||
679 entry->parent_resource_id() == directory->resource_id());
680
681 // Try to add the entry to resource map. 680 // Try to add the entry to resource map.
682 if (!AddEntryToResourceMap(entry)) { 681 if (!AddEntryToResourceMap(entry)) {
683 LOG(WARNING) << "Duplicate resource=" << entry->resource_id() 682 LOG(WARNING) << "Duplicate resource=" << entry->resource_id()
684 << ", title=" << entry->title(); 683 << ", title=" << entry->title();
685 return; 684 return;
686 } 685 }
687 686
688 // The entry name may have been changed due to prior name de-duplication. 687 // The entry name may have been changed due to prior name de-duplication.
689 // We need to first restore the file name based on the title before going 688 // We need to first restore the file name based on the title before going
690 // through name de-duplication again when it is added to another directory. 689 // through name de-duplication again when it is added to another directory.
691 SetBaseNameFromTitle(entry); 690 SetBaseNameFromTitle(entry);
692 691
693 // Do file name de-duplication - find files with the same name and 692 // Do file name de-duplication - find files with the same name and
694 // append a name modifier to the name. 693 // append a name modifier to the name.
695 int modifier = 1; 694 int modifier = 1;
696 base::FilePath full_file_name(entry->base_name()); 695 base::FilePath full_file_name(entry->base_name());
697 const std::string extension = full_file_name.Extension(); 696 const std::string extension = full_file_name.Extension();
698 const std::string file_name = full_file_name.RemoveExtension().value(); 697 const std::string file_name = full_file_name.RemoveExtension().value();
699 while (!FindDirectoryChild(directory, full_file_name.value()).empty()) { 698 while (!FindDirectoryChild(entry->parent_resource_id(),
699 full_file_name.value()).empty()) {
700 if (!extension.empty()) { 700 if (!extension.empty()) {
701 full_file_name = base::FilePath(base::StringPrintf("%s (%d)%s", 701 full_file_name = base::FilePath(base::StringPrintf("%s (%d)%s",
702 file_name.c_str(), 702 file_name.c_str(),
703 ++modifier, 703 ++modifier,
704 extension.c_str())); 704 extension.c_str()));
705 } else { 705 } else {
706 full_file_name = base::FilePath(base::StringPrintf("%s (%d)", 706 full_file_name = base::FilePath(base::StringPrintf("%s (%d)",
707 file_name.c_str(), 707 file_name.c_str(),
708 ++modifier)); 708 ++modifier));
709 } 709 }
710 } 710 }
711 entry->set_base_name(full_file_name.value()); 711 entry->set_base_name(full_file_name.value());
712 712
713 // Setup child and parent links. 713 // Setup child and parent links.
714 child_maps_[directory->resource_id()].insert( 714 child_maps_[entry->parent_resource_id()].insert(
715 std::make_pair(entry->base_name(), entry->resource_id())); 715 std::make_pair(entry->base_name(), entry->resource_id()));
716 entry->set_parent_resource_id(directory->resource_id());
717 } 716 }
718 717
719 void DriveResourceMetadata::RemoveDirectoryChild(DriveEntryProto* directory, 718 void DriveResourceMetadata::RemoveDirectoryChild(
720 DriveEntryProto* entry) { 719 const std::string& child_resource_id) {
721 DCHECK(directory->file_info().is_directory()); 720 DriveEntryProto* entry = GetEntryByResourceId(child_resource_id);
722 DetachEntryFromDirectory(directory, entry); 721 DCHECK(entry);
722 DetachEntryFromDirectory(child_resource_id);
723 if (entry->file_info().is_directory()) 723 if (entry->file_info().is_directory())
724 RemoveDirectoryChildren(entry); 724 RemoveDirectoryChildren(child_resource_id);
725 delete entry; 725 delete entry;
726 } 726 }
727 727
728 std::string DriveResourceMetadata::FindDirectoryChild( 728 std::string DriveResourceMetadata::FindDirectoryChild(
729 DriveEntryProto* directory, 729 const std::string& directory_resource_id,
730 const base::FilePath::StringType& file_name) { 730 const base::FilePath::StringType& file_name) {
731 DCHECK(directory->file_info().is_directory()); 731 const ChildMap& children = child_maps_[directory_resource_id];
732 const ChildMap& children = child_maps_[directory->resource_id()];
733 DriveResourceMetadata::ChildMap::const_iterator iter = 732 DriveResourceMetadata::ChildMap::const_iterator iter =
734 children.find(file_name); 733 children.find(file_name);
735 if (iter != children.end()) 734 if (iter != children.end())
736 return iter->second; 735 return iter->second;
737 return std::string(); 736 return std::string();
738 } 737 }
739 738
740 void DriveResourceMetadata::DetachEntryFromDirectory( 739 void DriveResourceMetadata::DetachEntryFromDirectory(
741 DriveEntryProto* directory, 740 const std::string& child_resource_id) {
742 DriveEntryProto* entry) { 741 DriveEntryProto* entry = GetEntryByResourceId(child_resource_id);
743 DCHECK(directory->file_info().is_directory());
744 DCHECK(entry); 742 DCHECK(entry);
745 743
746 const std::string& base_name(entry->base_name()); 744 const std::string& base_name(entry->base_name());
747 // entry must be present in this directory. 745 // entry must be present in this directory.
748 DCHECK_EQ(entry->resource_id(), FindDirectoryChild(directory, base_name)); 746 DCHECK_EQ(entry->resource_id(),
747 FindDirectoryChild(entry->parent_resource_id(), base_name));
749 // Remove entry from resource map first. 748 // Remove entry from resource map first.
750 RemoveEntryFromResourceMap(entry->resource_id()); 749 RemoveEntryFromResourceMap(entry->resource_id());
751 750
752 // Then delete it from tree. 751 // Then delete it from tree.
753 child_maps_[directory->resource_id()].erase(base_name); 752 child_maps_[entry->parent_resource_id()].erase(base_name);
754 753
755 entry->set_parent_resource_id(std::string()); 754 entry->set_parent_resource_id(std::string());
756 } 755 }
757 756
758 void DriveResourceMetadata::RemoveDirectoryChildren( 757 void DriveResourceMetadata::RemoveDirectoryChildren(
759 DriveEntryProto* directory) { 758 const std::string& directory_resource_id) {
760 DCHECK(directory->file_info().is_directory());
761 DriveResourceMetadata::ChildMap* children = 759 DriveResourceMetadata::ChildMap* children =
762 &child_maps_[directory->resource_id()]; 760 &child_maps_[directory_resource_id];
763 for (DriveResourceMetadata::ChildMap::iterator iter = children->begin(); 761 for (DriveResourceMetadata::ChildMap::iterator iter = children->begin();
764 iter != children->end(); ++iter) { 762 iter != children->end(); ++iter) {
765 DriveEntryProto* child = GetEntryByResourceId(iter->second); 763 DriveEntryProto* child = GetEntryByResourceId(iter->second);
766 DCHECK(child); 764 DCHECK(child);
767 // Remove directories recursively. 765 // Remove directories recursively.
768 if (child->file_info().is_directory()) 766 if (child->file_info().is_directory())
769 RemoveDirectoryChildren(child); 767 RemoveDirectoryChildren(child->resource_id());
770 768
771 RemoveEntryFromResourceMap(iter->second); 769 RemoveEntryFromResourceMap(iter->second);
772 delete child; 770 delete child;
773 } 771 }
774 child_maps_.erase(directory->resource_id()); 772 child_maps_.erase(directory_resource_id);
775 } 773 }
776 774
777 void DriveResourceMetadata::ProtoToDirectory(const DriveDirectoryProto& proto, 775 void DriveResourceMetadata::AddDescendantsFromProto(
778 DriveEntryProto* directory) { 776 const DriveDirectoryProto& proto) {
779 DCHECK(proto.drive_entry().file_info().is_directory()); 777 DCHECK(proto.drive_entry().file_info().is_directory());
780 DCHECK(!proto.drive_entry().has_file_specific_info()); 778 DCHECK(!proto.drive_entry().has_file_specific_info());
779 DCHECK(child_maps_[proto.drive_entry().resource_id()].empty());
781 780
782 *directory = CreateEntryWithProperBaseName(proto.drive_entry()); 781 // Add child files.
783
784 for (int i = 0; i < proto.child_files_size(); ++i) { 782 for (int i = 0; i < proto.child_files_size(); ++i) {
785 scoped_ptr<DriveEntryProto> file(new DriveEntryProto( 783 scoped_ptr<DriveEntryProto> file(new DriveEntryProto(
786 CreateEntryWithProperBaseName(proto.child_files(i)))); 784 CreateEntryWithProperBaseName(proto.child_files(i))));
787 AddEntryToDirectory(directory, file.release()); 785 DCHECK_EQ(proto.drive_entry().resource_id(), file->parent_resource_id());
786 AddEntryToDirectory(file.release());
788 } 787 }
788 // Add child directories recursively.
789 for (int i = 0; i < proto.child_directories_size(); ++i) { 789 for (int i = 0; i < proto.child_directories_size(); ++i) {
790 scoped_ptr<DriveEntryProto> child_dir(new DriveEntryProto); 790 scoped_ptr<DriveEntryProto> child_dir(new DriveEntryProto);
791 ProtoToDirectory(proto.child_directories(i), child_dir.get()); 791 *child_dir = CreateEntryWithProperBaseName(
792 AddEntryToDirectory(directory, child_dir.release()); 792 proto.child_directories(i).drive_entry());
793 DCHECK_EQ(proto.drive_entry().resource_id(),
794 child_dir->parent_resource_id());
795 AddEntryToDirectory(child_dir.release()); // Transfer ownership.
796 AddDescendantsFromProto(proto.child_directories(i));
793 } 797 }
794 } 798 }
795 799
796 void DriveResourceMetadata::DirectoryToProto(DriveEntryProto* directory, 800 void DriveResourceMetadata::DirectoryToProto(
797 DriveDirectoryProto* proto) { 801 const std::string& directory_resource_id,
802 DriveDirectoryProto* proto) {
803 DriveEntryProto* directory = GetEntryByResourceId(directory_resource_id);
804 DCHECK(directory);
798 *proto->mutable_drive_entry() = *directory; 805 *proto->mutable_drive_entry() = *directory;
799 DCHECK(proto->drive_entry().file_info().is_directory()); 806 DCHECK(proto->drive_entry().file_info().is_directory());
800 807
801 const ChildMap& children = child_maps_[directory->resource_id()]; 808 const ChildMap& children = child_maps_[directory_resource_id];
802 for (ChildMap::const_iterator iter = children.begin(); 809 for (ChildMap::const_iterator iter = children.begin();
803 iter != children.end(); ++iter) { 810 iter != children.end(); ++iter) {
804 DriveEntryProto* entry = GetEntryByResourceId(iter->second); 811 DriveEntryProto* entry = GetEntryByResourceId(iter->second);
805 DCHECK(entry); 812 DCHECK(entry);
806 if (entry->file_info().is_directory()) 813 if (entry->file_info().is_directory())
807 DirectoryToProto(entry, proto->add_child_directories()); 814 DirectoryToProto(entry->resource_id(), proto->add_child_directories());
808 else 815 else
809 *proto->add_child_files() = *entry; 816 *proto->add_child_files() = *entry;
810 } 817 }
811 } 818 }
812 819
813 scoped_ptr<DriveEntryProtoVector> 820 scoped_ptr<DriveEntryProtoVector>
814 DriveResourceMetadata::DirectoryChildrenToProtoVector( 821 DriveResourceMetadata::DirectoryChildrenToProtoVector(
815 DriveEntryProto* directory) { 822 const std::string& directory_resource_id) {
816 DCHECK(directory->file_info().is_directory());
817 scoped_ptr<DriveEntryProtoVector> entries(new DriveEntryProtoVector); 823 scoped_ptr<DriveEntryProtoVector> entries(new DriveEntryProtoVector);
818 const ChildMap& children = child_maps_[directory->resource_id()]; 824 const ChildMap& children = child_maps_[directory_resource_id];
819 for (ChildMap::const_iterator iter = children.begin(); 825 for (ChildMap::const_iterator iter = children.begin();
820 iter != children.end(); ++iter) { 826 iter != children.end(); ++iter) {
821 const DriveEntryProto& proto = *GetEntryByResourceId(iter->second); 827 const DriveEntryProto* child = GetEntryByResourceId(iter->second);
822 entries->push_back(proto); 828 DCHECK(child);
829 entries->push_back(*child);
823 } 830 }
824 return entries.Pass(); 831 return entries.Pass();
825 } 832 }
826 833
827 } // namespace drive 834 } // namespace drive
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698