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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/drive/file_system.h"
6
7 #include "base/bind.h"
8 #include "base/file_util.h"
9 #include "base/prefs/pref_service.h"
10 #include "chrome/browser/chromeos/drive/change_list_loader.h"
11 #include "chrome/browser/chromeos/drive/directory_loader.h"
12 #include "chrome/browser/chromeos/drive/drive.pb.h"
13 #include "chrome/browser/chromeos/drive/file_cache.h"
14 #include "chrome/browser/chromeos/drive/file_system/copy_operation.h"
15 #include "chrome/browser/chromeos/drive/file_system/create_directory_operation.h"
16 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h"
17 #include "chrome/browser/chromeos/drive/file_system/download_operation.h"
18 #include "chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h"
19 #include "chrome/browser/chromeos/drive/file_system/move_operation.h"
20 #include "chrome/browser/chromeos/drive/file_system/open_file_operation.h"
21 #include "chrome/browser/chromeos/drive/file_system/remove_operation.h"
22 #include "chrome/browser/chromeos/drive/file_system/search_operation.h"
23 #include "chrome/browser/chromeos/drive/file_system/touch_operation.h"
24 #include "chrome/browser/chromeos/drive/file_system/truncate_operation.h"
25 #include "chrome/browser/chromeos/drive/file_system_observer.h"
26 #include "chrome/browser/chromeos/drive/file_system_util.h"
27 #include "chrome/browser/chromeos/drive/job_scheduler.h"
28 #include "chrome/browser/chromeos/drive/remove_stale_cache_files.h"
29 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
30 #include "chrome/browser/chromeos/drive/search_metadata.h"
31 #include "chrome/browser/chromeos/drive/sync_client.h"
32 #include "chrome/browser/drive/drive_service_interface.h"
33 #include "chrome/common/pref_names.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "google_apis/drive/drive_api_parser.h"
36
37 using content::BrowserThread;
38
39 namespace drive {
40 namespace {
41
42 // Gets a ResourceEntry from the metadata, and overwrites its file info when the
43 // cached file is dirty.
GetLocallyStoredResourceEntry(internal::ResourceMetadata * resource_metadata,internal::FileCache * cache,const base::FilePath & file_path,ResourceEntry * entry)44 FileError GetLocallyStoredResourceEntry(
45 internal::ResourceMetadata* resource_metadata,
46 internal::FileCache* cache,
47 const base::FilePath& file_path,
48 ResourceEntry* entry) {
49 std::string local_id;
50 FileError error = resource_metadata->GetIdByPath(file_path, &local_id);
51 if (error != FILE_ERROR_OK)
52 return error;
53
54 error = resource_metadata->GetResourceEntryById(local_id, entry);
55 if (error != FILE_ERROR_OK)
56 return error;
57
58 // For entries that will never be cached, use the original resource entry
59 // as is.
60 if (!entry->has_file_specific_info() ||
61 entry->file_specific_info().is_hosted_document())
62 return FILE_ERROR_OK;
63
64 // When cache is not found, use the original resource entry as is.
65 if (!entry->file_specific_info().has_cache_state())
66 return FILE_ERROR_OK;
67
68 // When cache is non-dirty and obsolete (old hash), use the original entry.
69 if (!entry->file_specific_info().cache_state().is_dirty() &&
70 entry->file_specific_info().md5() !=
71 entry->file_specific_info().cache_state().md5())
72 return FILE_ERROR_OK;
73
74 // If there's a valid cache, obtain the file info from the cache file itself.
75 base::FilePath local_cache_path;
76 error = cache->GetFile(local_id, &local_cache_path);
77 if (error != FILE_ERROR_OK)
78 return error;
79
80 base::File::Info file_info;
81 if (!base::GetFileInfo(local_cache_path, &file_info))
82 return FILE_ERROR_NOT_FOUND;
83
84 entry->mutable_file_info()->set_size(file_info.size);
85 return FILE_ERROR_OK;
86 }
87
88 // Runs the callback with parameters.
RunGetResourceEntryCallback(const GetResourceEntryCallback & callback,scoped_ptr<ResourceEntry> entry,FileError error)89 void RunGetResourceEntryCallback(const GetResourceEntryCallback& callback,
90 scoped_ptr<ResourceEntry> entry,
91 FileError error) {
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
93 DCHECK(!callback.is_null());
94
95 if (error != FILE_ERROR_OK)
96 entry.reset();
97 callback.Run(error, entry.Pass());
98 }
99
100 // Used to implement Pin().
PinInternal(internal::ResourceMetadata * resource_metadata,internal::FileCache * cache,const base::FilePath & file_path,std::string * local_id)101 FileError PinInternal(internal::ResourceMetadata* resource_metadata,
102 internal::FileCache* cache,
103 const base::FilePath& file_path,
104 std::string* local_id) {
105 FileError error = resource_metadata->GetIdByPath(file_path, local_id);
106 if (error != FILE_ERROR_OK)
107 return error;
108
109 ResourceEntry entry;
110 error = resource_metadata->GetResourceEntryById(*local_id, &entry);
111 if (error != FILE_ERROR_OK)
112 return error;
113
114 // TODO(hashimoto): Support pinning directories. crbug.com/127831
115 if (entry.file_info().is_directory())
116 return FILE_ERROR_NOT_A_FILE;
117
118 return cache->Pin(*local_id);
119 }
120
121 // Used to implement Unpin().
UnpinInternal(internal::ResourceMetadata * resource_metadata,internal::FileCache * cache,const base::FilePath & file_path,std::string * local_id)122 FileError UnpinInternal(internal::ResourceMetadata* resource_metadata,
123 internal::FileCache* cache,
124 const base::FilePath& file_path,
125 std::string* local_id) {
126 FileError error = resource_metadata->GetIdByPath(file_path, local_id);
127 if (error != FILE_ERROR_OK)
128 return error;
129
130 return cache->Unpin(*local_id);
131 }
132
133 // Used to implement MarkCacheFileAsMounted().
MarkCacheFileAsMountedInternal(internal::ResourceMetadata * resource_metadata,internal::FileCache * cache,const base::FilePath & drive_file_path,base::FilePath * cache_file_path)134 FileError MarkCacheFileAsMountedInternal(
135 internal::ResourceMetadata* resource_metadata,
136 internal::FileCache* cache,
137 const base::FilePath& drive_file_path,
138 base::FilePath* cache_file_path) {
139 std::string local_id;
140 FileError error = resource_metadata->GetIdByPath(drive_file_path, &local_id);
141 if (error != FILE_ERROR_OK)
142 return error;
143
144 return cache->MarkAsMounted(local_id, cache_file_path);
145 }
146
147 // Runs the callback with arguments.
RunMarkMountedCallback(const MarkMountedCallback & callback,base::FilePath * cache_file_path,FileError error)148 void RunMarkMountedCallback(const MarkMountedCallback& callback,
149 base::FilePath* cache_file_path,
150 FileError error) {
151 DCHECK(!callback.is_null());
152 callback.Run(error, *cache_file_path);
153 }
154
155 // Callback for ResourceMetadata::GetLargestChangestamp.
156 // |callback| must not be null.
OnGetLargestChangestamp(FileSystemMetadata metadata,const GetFilesystemMetadataCallback & callback,const int64 * largest_changestamp,FileError error)157 void OnGetLargestChangestamp(
158 FileSystemMetadata metadata, // Will be modified.
159 const GetFilesystemMetadataCallback& callback,
160 const int64* largest_changestamp,
161 FileError error) {
162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
163 DCHECK(!callback.is_null());
164
165 metadata.largest_changestamp = *largest_changestamp;
166 callback.Run(metadata);
167 }
168
169 // Thin adapter to map GetFileCallback to FileOperationCallback.
GetFileCallbackToFileOperationCallbackAdapter(const FileOperationCallback & callback,FileError error,const base::FilePath & unused_file_path,scoped_ptr<ResourceEntry> unused_entry)170 void GetFileCallbackToFileOperationCallbackAdapter(
171 const FileOperationCallback& callback,
172 FileError error,
173 const base::FilePath& unused_file_path,
174 scoped_ptr<ResourceEntry> unused_entry) {
175 callback.Run(error);
176 }
177
178 // Clears |resource_metadata| and |cache|.
ResetOnBlockingPool(internal::ResourceMetadata * resource_metadata,internal::FileCache * cache)179 FileError ResetOnBlockingPool(internal::ResourceMetadata* resource_metadata,
180 internal::FileCache* cache) {
181 FileError error = resource_metadata->Reset();
182 if (error != FILE_ERROR_OK)
183 return error;
184 return cache->ClearAll() ? FILE_ERROR_OK : FILE_ERROR_FAILED;
185 }
186
187 // Part of GetPathFromResourceId().
188 // Obtains |file_path| from |resource_id|. The function should be run on the
189 // blocking pool.
GetPathFromResourceIdOnBlockingPool(internal::ResourceMetadata * resource_metadata,const std::string & resource_id,base::FilePath * file_path)190 FileError GetPathFromResourceIdOnBlockingPool(
191 internal::ResourceMetadata* resource_metadata,
192 const std::string& resource_id,
193 base::FilePath* file_path) {
194 std::string local_id;
195 const FileError error =
196 resource_metadata->GetIdByResourceId(resource_id, &local_id);
197 if (error != FILE_ERROR_OK)
198 return error;
199 return resource_metadata->GetFilePath(local_id, file_path);
200 }
201
202 // Part of GetPathFromResourceId().
203 // Called when GetPathFromResourceIdInBlockingPool is complete.
GetPathFromResourceIdAfterGetPath(base::FilePath * file_path,const GetFilePathCallback & callback,FileError error)204 void GetPathFromResourceIdAfterGetPath(base::FilePath* file_path,
205 const GetFilePathCallback& callback,
206 FileError error) {
207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
208 callback.Run(error, *file_path);
209 }
210
211 // Excludes hosted documents from the given entries.
212 // Used to implement ReadDirectory().
FilterHostedDocuments(const ReadDirectoryEntriesCallback & callback,scoped_ptr<ResourceEntryVector> entries)213 void FilterHostedDocuments(const ReadDirectoryEntriesCallback& callback,
214 scoped_ptr<ResourceEntryVector> entries) {
215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
216 DCHECK(!callback.is_null());
217
218 if (entries) {
219 // TODO(kinaba): Stop handling hide_hosted_docs here. crbug.com/256520.
220 scoped_ptr<ResourceEntryVector> filtered(new ResourceEntryVector);
221 for (size_t i = 0; i < entries->size(); ++i) {
222 if (entries->at(i).file_specific_info().is_hosted_document()) {
223 continue;
224 }
225 filtered->push_back(entries->at(i));
226 }
227 entries.swap(filtered);
228 }
229 callback.Run(entries.Pass());
230 }
231
232 // Adapter for using FileOperationCallback as google_apis::EntryActionCallback.
RunFileOperationCallbackAsEntryActionCallback(const FileOperationCallback & callback,google_apis::GDataErrorCode error)233 void RunFileOperationCallbackAsEntryActionCallback(
234 const FileOperationCallback& callback,
235 google_apis::GDataErrorCode error) {
236 callback.Run(GDataToFileError(error));
237 }
238
239 } // namespace
240
241 struct FileSystem::CreateDirectoryParams {
242 base::FilePath directory_path;
243 bool is_exclusive;
244 bool is_recursive;
245 FileOperationCallback callback;
246 };
247
FileSystem(PrefService * pref_service,EventLogger * logger,internal::FileCache * cache,DriveServiceInterface * drive_service,JobScheduler * scheduler,internal::ResourceMetadata * resource_metadata,base::SequencedTaskRunner * blocking_task_runner,const base::FilePath & temporary_file_directory)248 FileSystem::FileSystem(
249 PrefService* pref_service,
250 EventLogger* logger,
251 internal::FileCache* cache,
252 DriveServiceInterface* drive_service,
253 JobScheduler* scheduler,
254 internal::ResourceMetadata* resource_metadata,
255 base::SequencedTaskRunner* blocking_task_runner,
256 const base::FilePath& temporary_file_directory)
257 : pref_service_(pref_service),
258 logger_(logger),
259 cache_(cache),
260 drive_service_(drive_service),
261 scheduler_(scheduler),
262 resource_metadata_(resource_metadata),
263 last_update_check_error_(FILE_ERROR_OK),
264 blocking_task_runner_(blocking_task_runner),
265 temporary_file_directory_(temporary_file_directory),
266 weak_ptr_factory_(this) {
267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
268
269 ResetComponents();
270 }
271
~FileSystem()272 FileSystem::~FileSystem() {
273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
274
275 directory_loader_->RemoveObserver(this);
276 change_list_loader_->RemoveObserver(this);
277 }
278
Reset(const FileOperationCallback & callback)279 void FileSystem::Reset(const FileOperationCallback& callback) {
280 // Discard the current loader and operation objects and renew them. This is to
281 // avoid that changes initiated before the metadata reset is applied after the
282 // reset, which may cause an inconsistent state.
283 // TODO(kinaba): callbacks held in the subcomponents are discarded. We might
284 // want to have a way to abort and flush callbacks in in-flight operations.
285 ResetComponents();
286
287 base::PostTaskAndReplyWithResult(
288 blocking_task_runner_,
289 FROM_HERE,
290 base::Bind(&ResetOnBlockingPool, resource_metadata_, cache_),
291 callback);
292 }
293
ResetComponents()294 void FileSystem::ResetComponents() {
295 file_system::OperationObserver* observer = this;
296
297 about_resource_loader_.reset(new internal::AboutResourceLoader(scheduler_));
298 loader_controller_.reset(new internal::LoaderController);
299 change_list_loader_.reset(new internal::ChangeListLoader(
300 logger_,
301 blocking_task_runner_.get(),
302 resource_metadata_,
303 scheduler_,
304 about_resource_loader_.get(),
305 loader_controller_.get()));
306 change_list_loader_->AddObserver(this);
307 directory_loader_.reset(new internal::DirectoryLoader(
308 logger_,
309 blocking_task_runner_.get(),
310 resource_metadata_,
311 scheduler_,
312 about_resource_loader_.get(),
313 loader_controller_.get()));
314 directory_loader_->AddObserver(this);
315
316 sync_client_.reset(new internal::SyncClient(blocking_task_runner_.get(),
317 observer,
318 scheduler_,
319 resource_metadata_,
320 cache_,
321 loader_controller_.get(),
322 temporary_file_directory_));
323
324 copy_operation_.reset(
325 new file_system::CopyOperation(
326 blocking_task_runner_.get(),
327 observer,
328 scheduler_,
329 resource_metadata_,
330 cache_,
331 drive_service_->GetResourceIdCanonicalizer()));
332 create_directory_operation_.reset(new file_system::CreateDirectoryOperation(
333 blocking_task_runner_.get(), observer, resource_metadata_));
334 create_file_operation_.reset(
335 new file_system::CreateFileOperation(blocking_task_runner_.get(),
336 observer,
337 resource_metadata_));
338 move_operation_.reset(
339 new file_system::MoveOperation(blocking_task_runner_.get(),
340 observer,
341 resource_metadata_));
342 open_file_operation_.reset(
343 new file_system::OpenFileOperation(blocking_task_runner_.get(),
344 observer,
345 scheduler_,
346 resource_metadata_,
347 cache_,
348 temporary_file_directory_));
349 remove_operation_.reset(
350 new file_system::RemoveOperation(blocking_task_runner_.get(),
351 observer,
352 resource_metadata_,
353 cache_));
354 touch_operation_.reset(new file_system::TouchOperation(
355 blocking_task_runner_.get(), observer, resource_metadata_));
356 truncate_operation_.reset(
357 new file_system::TruncateOperation(blocking_task_runner_.get(),
358 observer,
359 scheduler_,
360 resource_metadata_,
361 cache_,
362 temporary_file_directory_));
363 download_operation_.reset(
364 new file_system::DownloadOperation(blocking_task_runner_.get(),
365 observer,
366 scheduler_,
367 resource_metadata_,
368 cache_,
369 temporary_file_directory_));
370 search_operation_.reset(new file_system::SearchOperation(
371 blocking_task_runner_.get(), scheduler_, resource_metadata_,
372 loader_controller_.get()));
373 get_file_for_saving_operation_.reset(
374 new file_system::GetFileForSavingOperation(logger_,
375 blocking_task_runner_.get(),
376 observer,
377 scheduler_,
378 resource_metadata_,
379 cache_,
380 temporary_file_directory_));
381 }
382
CheckForUpdates()383 void FileSystem::CheckForUpdates() {
384 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
385 DVLOG(1) << "CheckForUpdates";
386
387 change_list_loader_->CheckForUpdates(
388 base::Bind(&FileSystem::OnUpdateChecked, weak_ptr_factory_.GetWeakPtr()));
389 }
390
OnUpdateChecked(FileError error)391 void FileSystem::OnUpdateChecked(FileError error) {
392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
393 DVLOG(1) << "CheckForUpdates finished: " << FileErrorToString(error);
394 last_update_check_time_ = base::Time::Now();
395 last_update_check_error_ = error;
396 }
397
AddObserver(FileSystemObserver * observer)398 void FileSystem::AddObserver(FileSystemObserver* observer) {
399 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
400 observers_.AddObserver(observer);
401 }
402
RemoveObserver(FileSystemObserver * observer)403 void FileSystem::RemoveObserver(FileSystemObserver* observer) {
404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
405 observers_.RemoveObserver(observer);
406 }
407
TransferFileFromLocalToRemote(const base::FilePath & local_src_file_path,const base::FilePath & remote_dest_file_path,const FileOperationCallback & callback)408 void FileSystem::TransferFileFromLocalToRemote(
409 const base::FilePath& local_src_file_path,
410 const base::FilePath& remote_dest_file_path,
411 const FileOperationCallback& callback) {
412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
413 DCHECK(!callback.is_null());
414 copy_operation_->TransferFileFromLocalToRemote(local_src_file_path,
415 remote_dest_file_path,
416 callback);
417 }
418
Copy(const base::FilePath & src_file_path,const base::FilePath & dest_file_path,bool preserve_last_modified,const FileOperationCallback & callback)419 void FileSystem::Copy(const base::FilePath& src_file_path,
420 const base::FilePath& dest_file_path,
421 bool preserve_last_modified,
422 const FileOperationCallback& callback) {
423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
424 DCHECK(!callback.is_null());
425 copy_operation_->Copy(
426 src_file_path, dest_file_path, preserve_last_modified, callback);
427 }
428
Move(const base::FilePath & src_file_path,const base::FilePath & dest_file_path,const FileOperationCallback & callback)429 void FileSystem::Move(const base::FilePath& src_file_path,
430 const base::FilePath& dest_file_path,
431 const FileOperationCallback& callback) {
432 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
433 DCHECK(!callback.is_null());
434 move_operation_->Move(src_file_path, dest_file_path, callback);
435 }
436
Remove(const base::FilePath & file_path,bool is_recursive,const FileOperationCallback & callback)437 void FileSystem::Remove(const base::FilePath& file_path,
438 bool is_recursive,
439 const FileOperationCallback& callback) {
440 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
441 DCHECK(!callback.is_null());
442 remove_operation_->Remove(file_path, is_recursive, callback);
443 }
444
CreateDirectory(const base::FilePath & directory_path,bool is_exclusive,bool is_recursive,const FileOperationCallback & callback)445 void FileSystem::CreateDirectory(
446 const base::FilePath& directory_path,
447 bool is_exclusive,
448 bool is_recursive,
449 const FileOperationCallback& callback) {
450 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
451 DCHECK(!callback.is_null());
452
453 CreateDirectoryParams params;
454 params.directory_path = directory_path;
455 params.is_exclusive = is_exclusive;
456 params.is_recursive = is_recursive;
457 params.callback = callback;
458
459 // Ensure its parent directory is loaded to the local metadata.
460 ReadDirectory(directory_path.DirName(),
461 ReadDirectoryEntriesCallback(),
462 base::Bind(&FileSystem::CreateDirectoryAfterRead,
463 weak_ptr_factory_.GetWeakPtr(), params));
464 }
465
CreateDirectoryAfterRead(const CreateDirectoryParams & params,FileError error)466 void FileSystem::CreateDirectoryAfterRead(const CreateDirectoryParams& params,
467 FileError error) {
468 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
469 DCHECK(!params.callback.is_null());
470
471 DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. "
472 << FileErrorToString(error);
473
474 create_directory_operation_->CreateDirectory(
475 params.directory_path, params.is_exclusive, params.is_recursive,
476 params.callback);
477 }
478
CreateFile(const base::FilePath & file_path,bool is_exclusive,const std::string & mime_type,const FileOperationCallback & callback)479 void FileSystem::CreateFile(const base::FilePath& file_path,
480 bool is_exclusive,
481 const std::string& mime_type,
482 const FileOperationCallback& callback) {
483 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
484 DCHECK(!callback.is_null());
485 create_file_operation_->CreateFile(
486 file_path, is_exclusive, mime_type, callback);
487 }
488
TouchFile(const base::FilePath & file_path,const base::Time & last_access_time,const base::Time & last_modified_time,const FileOperationCallback & callback)489 void FileSystem::TouchFile(const base::FilePath& file_path,
490 const base::Time& last_access_time,
491 const base::Time& last_modified_time,
492 const FileOperationCallback& callback) {
493 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
494 DCHECK(!callback.is_null());
495 touch_operation_->TouchFile(
496 file_path, last_access_time, last_modified_time, callback);
497 }
498
TruncateFile(const base::FilePath & file_path,int64 length,const FileOperationCallback & callback)499 void FileSystem::TruncateFile(const base::FilePath& file_path,
500 int64 length,
501 const FileOperationCallback& callback) {
502 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
503 DCHECK(!callback.is_null());
504 truncate_operation_->Truncate(file_path, length, callback);
505 }
506
Pin(const base::FilePath & file_path,const FileOperationCallback & callback)507 void FileSystem::Pin(const base::FilePath& file_path,
508 const FileOperationCallback& callback) {
509 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
510 DCHECK(!callback.is_null());
511
512 std::string* local_id = new std::string;
513 base::PostTaskAndReplyWithResult(
514 blocking_task_runner_,
515 FROM_HERE,
516 base::Bind(&PinInternal, resource_metadata_, cache_, file_path, local_id),
517 base::Bind(&FileSystem::FinishPin,
518 weak_ptr_factory_.GetWeakPtr(),
519 callback,
520 base::Owned(local_id)));
521 }
522
FinishPin(const FileOperationCallback & callback,const std::string * local_id,FileError error)523 void FileSystem::FinishPin(const FileOperationCallback& callback,
524 const std::string* local_id,
525 FileError error) {
526 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
527 DCHECK(!callback.is_null());
528
529 if (error == FILE_ERROR_OK)
530 sync_client_->AddFetchTask(*local_id);
531 callback.Run(error);
532 }
533
Unpin(const base::FilePath & file_path,const FileOperationCallback & callback)534 void FileSystem::Unpin(const base::FilePath& file_path,
535 const FileOperationCallback& callback) {
536 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
537 DCHECK(!callback.is_null());
538
539 std::string* local_id = new std::string;
540 base::PostTaskAndReplyWithResult(
541 blocking_task_runner_,
542 FROM_HERE,
543 base::Bind(&UnpinInternal,
544 resource_metadata_,
545 cache_,
546 file_path,
547 local_id),
548 base::Bind(&FileSystem::FinishUnpin,
549 weak_ptr_factory_.GetWeakPtr(),
550 callback,
551 base::Owned(local_id)));
552 }
553
FinishUnpin(const FileOperationCallback & callback,const std::string * local_id,FileError error)554 void FileSystem::FinishUnpin(const FileOperationCallback& callback,
555 const std::string* local_id,
556 FileError error) {
557 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
558 DCHECK(!callback.is_null());
559
560 if (error == FILE_ERROR_OK)
561 sync_client_->RemoveFetchTask(*local_id);
562 callback.Run(error);
563 }
564
GetFile(const base::FilePath & file_path,const GetFileCallback & callback)565 void FileSystem::GetFile(const base::FilePath& file_path,
566 const GetFileCallback& callback) {
567 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
568 DCHECK(!callback.is_null());
569
570 download_operation_->EnsureFileDownloadedByPath(
571 file_path,
572 ClientContext(USER_INITIATED),
573 GetFileContentInitializedCallback(),
574 google_apis::GetContentCallback(),
575 callback);
576 }
577
GetFileForSaving(const base::FilePath & file_path,const GetFileCallback & callback)578 void FileSystem::GetFileForSaving(const base::FilePath& file_path,
579 const GetFileCallback& callback) {
580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
581 DCHECK(!callback.is_null());
582
583 get_file_for_saving_operation_->GetFileForSaving(file_path, callback);
584 }
585
GetFileContent(const base::FilePath & file_path,const GetFileContentInitializedCallback & initialized_callback,const google_apis::GetContentCallback & get_content_callback,const FileOperationCallback & completion_callback)586 base::Closure FileSystem::GetFileContent(
587 const base::FilePath& file_path,
588 const GetFileContentInitializedCallback& initialized_callback,
589 const google_apis::GetContentCallback& get_content_callback,
590 const FileOperationCallback& completion_callback) {
591 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
592 DCHECK(!initialized_callback.is_null());
593 DCHECK(!get_content_callback.is_null());
594 DCHECK(!completion_callback.is_null());
595
596 return download_operation_->EnsureFileDownloadedByPath(
597 file_path,
598 ClientContext(USER_INITIATED),
599 initialized_callback,
600 get_content_callback,
601 base::Bind(&GetFileCallbackToFileOperationCallbackAdapter,
602 completion_callback));
603 }
604
GetResourceEntry(const base::FilePath & file_path,const GetResourceEntryCallback & callback)605 void FileSystem::GetResourceEntry(
606 const base::FilePath& file_path,
607 const GetResourceEntryCallback& callback) {
608 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
609 DCHECK(!callback.is_null());
610
611 ReadDirectory(file_path.DirName(),
612 ReadDirectoryEntriesCallback(),
613 base::Bind(&FileSystem::GetResourceEntryAfterRead,
614 weak_ptr_factory_.GetWeakPtr(),
615 file_path,
616 callback));
617 }
618
GetResourceEntryAfterRead(const base::FilePath & file_path,const GetResourceEntryCallback & callback,FileError error)619 void FileSystem::GetResourceEntryAfterRead(
620 const base::FilePath& file_path,
621 const GetResourceEntryCallback& callback,
622 FileError error) {
623 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
624 DCHECK(!callback.is_null());
625
626 DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. "
627 << FileErrorToString(error);
628
629 scoped_ptr<ResourceEntry> entry(new ResourceEntry);
630 ResourceEntry* entry_ptr = entry.get();
631 base::PostTaskAndReplyWithResult(
632 blocking_task_runner_,
633 FROM_HERE,
634 base::Bind(&GetLocallyStoredResourceEntry,
635 resource_metadata_,
636 cache_,
637 file_path,
638 entry_ptr),
639 base::Bind(&RunGetResourceEntryCallback, callback, base::Passed(&entry)));
640 }
641
ReadDirectory(const base::FilePath & directory_path,const ReadDirectoryEntriesCallback & entries_callback_in,const FileOperationCallback & completion_callback)642 void FileSystem::ReadDirectory(
643 const base::FilePath& directory_path,
644 const ReadDirectoryEntriesCallback& entries_callback_in,
645 const FileOperationCallback& completion_callback) {
646 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
647 DCHECK(!completion_callback.is_null());
648
649 const bool hide_hosted_docs =
650 pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles);
651 ReadDirectoryEntriesCallback entries_callback = entries_callback_in;
652 if (!entries_callback.is_null() && hide_hosted_docs)
653 entries_callback = base::Bind(&FilterHostedDocuments, entries_callback);
654
655 directory_loader_->ReadDirectory(
656 directory_path, entries_callback, completion_callback);
657
658 // Also start loading all of the user's contents.
659 change_list_loader_->LoadIfNeeded(
660 base::Bind(&util::EmptyFileOperationCallback));
661 }
662
GetAvailableSpace(const GetAvailableSpaceCallback & callback)663 void FileSystem::GetAvailableSpace(
664 const GetAvailableSpaceCallback& callback) {
665 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
666 DCHECK(!callback.is_null());
667
668 about_resource_loader_->GetAboutResource(
669 base::Bind(&FileSystem::OnGetAboutResource,
670 weak_ptr_factory_.GetWeakPtr(),
671 callback));
672 }
673
OnGetAboutResource(const GetAvailableSpaceCallback & callback,google_apis::GDataErrorCode status,scoped_ptr<google_apis::AboutResource> about_resource)674 void FileSystem::OnGetAboutResource(
675 const GetAvailableSpaceCallback& callback,
676 google_apis::GDataErrorCode status,
677 scoped_ptr<google_apis::AboutResource> about_resource) {
678 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
679 DCHECK(!callback.is_null());
680
681 FileError error = GDataToFileError(status);
682 if (error != FILE_ERROR_OK) {
683 callback.Run(error, -1, -1);
684 return;
685 }
686 DCHECK(about_resource);
687
688 callback.Run(FILE_ERROR_OK,
689 about_resource->quota_bytes_total(),
690 about_resource->quota_bytes_used());
691 }
692
GetShareUrl(const base::FilePath & file_path,const GURL & embed_origin,const GetShareUrlCallback & callback)693 void FileSystem::GetShareUrl(const base::FilePath& file_path,
694 const GURL& embed_origin,
695 const GetShareUrlCallback& callback) {
696 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
697 DCHECK(!callback.is_null());
698
699 // Resolve the resource id.
700 ResourceEntry* entry = new ResourceEntry;
701 base::PostTaskAndReplyWithResult(
702 blocking_task_runner_.get(),
703 FROM_HERE,
704 base::Bind(&internal::ResourceMetadata::GetResourceEntryByPath,
705 base::Unretained(resource_metadata_),
706 file_path,
707 entry),
708 base::Bind(&FileSystem::GetShareUrlAfterGetResourceEntry,
709 weak_ptr_factory_.GetWeakPtr(),
710 file_path,
711 embed_origin,
712 callback,
713 base::Owned(entry)));
714 }
715
GetShareUrlAfterGetResourceEntry(const base::FilePath & file_path,const GURL & embed_origin,const GetShareUrlCallback & callback,ResourceEntry * entry,FileError error)716 void FileSystem::GetShareUrlAfterGetResourceEntry(
717 const base::FilePath& file_path,
718 const GURL& embed_origin,
719 const GetShareUrlCallback& callback,
720 ResourceEntry* entry,
721 FileError error) {
722 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
723 DCHECK(!callback.is_null());
724
725 if (error != FILE_ERROR_OK) {
726 callback.Run(error, GURL());
727 return;
728 }
729 if (entry->resource_id().empty()) {
730 // This entry does not exist on the server. Just return.
731 callback.Run(FILE_ERROR_FAILED, GURL());
732 return;
733 }
734
735 scheduler_->GetShareUrl(
736 entry->resource_id(),
737 embed_origin,
738 ClientContext(USER_INITIATED),
739 base::Bind(&FileSystem::OnGetResourceEntryForGetShareUrl,
740 weak_ptr_factory_.GetWeakPtr(),
741 callback));
742 }
743
OnGetResourceEntryForGetShareUrl(const GetShareUrlCallback & callback,google_apis::GDataErrorCode status,const GURL & share_url)744 void FileSystem::OnGetResourceEntryForGetShareUrl(
745 const GetShareUrlCallback& callback,
746 google_apis::GDataErrorCode status,
747 const GURL& share_url) {
748 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
749 DCHECK(!callback.is_null());
750
751 FileError error = GDataToFileError(status);
752 if (error != FILE_ERROR_OK) {
753 callback.Run(error, GURL());
754 return;
755 }
756
757 if (share_url.is_empty()) {
758 callback.Run(FILE_ERROR_FAILED, GURL());
759 return;
760 }
761
762 callback.Run(FILE_ERROR_OK, share_url);
763 }
764
Search(const std::string & search_query,const GURL & next_link,const SearchCallback & callback)765 void FileSystem::Search(const std::string& search_query,
766 const GURL& next_link,
767 const SearchCallback& callback) {
768 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
769 DCHECK(!callback.is_null());
770 search_operation_->Search(search_query, next_link, callback);
771 }
772
SearchMetadata(const std::string & query,int options,int at_most_num_matches,const SearchMetadataCallback & callback)773 void FileSystem::SearchMetadata(const std::string& query,
774 int options,
775 int at_most_num_matches,
776 const SearchMetadataCallback& callback) {
777 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
778
779 // TODO(satorux): Stop handling hide_hosted_docs here. crbug.com/256520.
780 if (pref_service_->GetBoolean(prefs::kDisableDriveHostedFiles))
781 options |= SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS;
782
783 drive::internal::SearchMetadata(blocking_task_runner_,
784 resource_metadata_,
785 query,
786 options,
787 at_most_num_matches,
788 callback);
789 }
790
OnDirectoryChangedByOperation(const base::FilePath & directory_path)791 void FileSystem::OnDirectoryChangedByOperation(
792 const base::FilePath& directory_path) {
793 OnDirectoryChanged(directory_path);
794 }
795
OnEntryUpdatedByOperation(const std::string & local_id)796 void FileSystem::OnEntryUpdatedByOperation(const std::string& local_id) {
797 sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id);
798 }
799
OnDriveSyncError(file_system::DriveSyncErrorType type,const std::string & local_id)800 void FileSystem::OnDriveSyncError(file_system::DriveSyncErrorType type,
801 const std::string& local_id) {
802 base::FilePath* file_path = new base::FilePath;
803 base::PostTaskAndReplyWithResult(
804 blocking_task_runner_,
805 FROM_HERE,
806 base::Bind(&internal::ResourceMetadata::GetFilePath,
807 base::Unretained(resource_metadata_),
808 local_id,
809 file_path),
810 base::Bind(&FileSystem::OnDriveSyncErrorAfterGetFilePath,
811 weak_ptr_factory_.GetWeakPtr(),
812 type,
813 base::Owned(file_path)));
814 }
815
OnDriveSyncErrorAfterGetFilePath(file_system::DriveSyncErrorType type,const base::FilePath * file_path,FileError error)816 void FileSystem::OnDriveSyncErrorAfterGetFilePath(
817 file_system::DriveSyncErrorType type,
818 const base::FilePath* file_path,
819 FileError error) {
820 if (error != FILE_ERROR_OK)
821 return;
822 FOR_EACH_OBSERVER(FileSystemObserver,
823 observers_,
824 OnDriveSyncError(type, *file_path));
825 }
826
OnDirectoryChanged(const base::FilePath & directory_path)827 void FileSystem::OnDirectoryChanged(const base::FilePath& directory_path) {
828 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
829
830 FOR_EACH_OBSERVER(FileSystemObserver, observers_,
831 OnDirectoryChanged(directory_path));
832 }
833
OnLoadFromServerComplete()834 void FileSystem::OnLoadFromServerComplete() {
835 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
836
837 sync_client_->StartCheckingExistingPinnedFiles();
838 }
839
OnInitialLoadComplete()840 void FileSystem::OnInitialLoadComplete() {
841 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
842
843 blocking_task_runner_->PostTask(FROM_HERE,
844 base::Bind(&internal::RemoveStaleCacheFiles,
845 cache_,
846 resource_metadata_));
847 sync_client_->StartProcessingBacklog();
848 }
849
GetMetadata(const GetFilesystemMetadataCallback & callback)850 void FileSystem::GetMetadata(
851 const GetFilesystemMetadataCallback& callback) {
852 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
853 DCHECK(!callback.is_null());
854
855 FileSystemMetadata metadata;
856 metadata.refreshing = change_list_loader_->IsRefreshing();
857
858 // Metadata related to delta update.
859 metadata.last_update_check_time = last_update_check_time_;
860 metadata.last_update_check_error = last_update_check_error_;
861
862 int64* largest_changestamp = new int64(0);
863 base::PostTaskAndReplyWithResult(
864 blocking_task_runner_,
865 FROM_HERE,
866 base::Bind(&internal::ResourceMetadata::GetLargestChangestamp,
867 base::Unretained(resource_metadata_), largest_changestamp),
868 base::Bind(&OnGetLargestChangestamp, metadata, callback,
869 base::Owned(largest_changestamp)));
870 }
871
MarkCacheFileAsMounted(const base::FilePath & drive_file_path,const MarkMountedCallback & callback)872 void FileSystem::MarkCacheFileAsMounted(
873 const base::FilePath& drive_file_path,
874 const MarkMountedCallback& callback) {
875 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
876 DCHECK(!callback.is_null());
877
878 base::FilePath* cache_file_path = new base::FilePath;
879 base::PostTaskAndReplyWithResult(
880 blocking_task_runner_,
881 FROM_HERE,
882 base::Bind(&MarkCacheFileAsMountedInternal,
883 resource_metadata_,
884 cache_,
885 drive_file_path,
886 cache_file_path),
887 base::Bind(&RunMarkMountedCallback,
888 callback,
889 base::Owned(cache_file_path)));
890 }
891
MarkCacheFileAsUnmounted(const base::FilePath & cache_file_path,const FileOperationCallback & callback)892 void FileSystem::MarkCacheFileAsUnmounted(
893 const base::FilePath& cache_file_path,
894 const FileOperationCallback& callback) {
895 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
896 DCHECK(!callback.is_null());
897
898 if (!cache_->IsUnderFileCacheDirectory(cache_file_path)) {
899 callback.Run(FILE_ERROR_FAILED);
900 return;
901 }
902
903 base::PostTaskAndReplyWithResult(
904 blocking_task_runner_,
905 FROM_HERE,
906 base::Bind(&internal::FileCache::MarkAsUnmounted,
907 base::Unretained(cache_),
908 cache_file_path),
909 callback);
910 }
911
AddPermission(const base::FilePath & drive_file_path,const std::string & email,google_apis::drive::PermissionRole role,const FileOperationCallback & callback)912 void FileSystem::AddPermission(const base::FilePath& drive_file_path,
913 const std::string& email,
914 google_apis::drive::PermissionRole role,
915 const FileOperationCallback& callback) {
916 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
917 DCHECK(!callback.is_null());
918
919 // Resolve the resource id.
920 ResourceEntry* const entry = new ResourceEntry;
921 base::PostTaskAndReplyWithResult(
922 blocking_task_runner_.get(),
923 FROM_HERE,
924 base::Bind(&internal::ResourceMetadata::GetResourceEntryByPath,
925 base::Unretained(resource_metadata_),
926 drive_file_path,
927 entry),
928 base::Bind(&FileSystem::AddPermissionAfterGetResourceEntry,
929 weak_ptr_factory_.GetWeakPtr(),
930 email,
931 role,
932 callback,
933 base::Owned(entry)));
934 }
935
AddPermissionAfterGetResourceEntry(const std::string & email,google_apis::drive::PermissionRole role,const FileOperationCallback & callback,ResourceEntry * entry,FileError error)936 void FileSystem::AddPermissionAfterGetResourceEntry(
937 const std::string& email,
938 google_apis::drive::PermissionRole role,
939 const FileOperationCallback& callback,
940 ResourceEntry* entry,
941 FileError error) {
942 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
943
944 if (error != FILE_ERROR_OK) {
945 callback.Run(error);
946 return;
947 }
948
949 scheduler_->AddPermission(
950 entry->resource_id(),
951 email,
952 role,
953 base::Bind(&RunFileOperationCallbackAsEntryActionCallback, callback));
954 }
955
OpenFile(const base::FilePath & file_path,OpenMode open_mode,const std::string & mime_type,const OpenFileCallback & callback)956 void FileSystem::OpenFile(const base::FilePath& file_path,
957 OpenMode open_mode,
958 const std::string& mime_type,
959 const OpenFileCallback& callback) {
960 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
961 DCHECK(!callback.is_null());
962
963 open_file_operation_->OpenFile(file_path, open_mode, mime_type, callback);
964 }
965
GetPathFromResourceId(const std::string & resource_id,const GetFilePathCallback & callback)966 void FileSystem::GetPathFromResourceId(const std::string& resource_id,
967 const GetFilePathCallback& callback) {
968 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
969 DCHECK(!callback.is_null());
970
971 base::FilePath* const file_path = new base::FilePath();
972 base::PostTaskAndReplyWithResult(
973 blocking_task_runner_,
974 FROM_HERE,
975 base::Bind(&GetPathFromResourceIdOnBlockingPool,
976 resource_metadata_,
977 resource_id,
978 file_path),
979 base::Bind(&GetPathFromResourceIdAfterGetPath,
980 base::Owned(file_path),
981 callback));
982 }
983 } // namespace drive
984