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/update_operation.h" 6 7 #include "base/platform_file.h" 8 #include "chrome/browser/chromeos/drive/drive.pb.h" 9 #include "chrome/browser/chromeos/drive/file_cache.h" 10 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h" 11 #include "chrome/browser/chromeos/drive/file_system_util.h" 12 #include "chrome/browser/chromeos/drive/job_scheduler.h" 13 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h" 14 #include "chrome/browser/chromeos/drive/resource_metadata.h" 15 #include "chrome/browser/drive/drive_api_util.h" 16 #include "content/public/browser/browser_thread.h" 17 18 using content::BrowserThread; 19 20 namespace drive { 21 namespace file_system { 22 23 struct UpdateOperation::LocalState { 24 LocalState() : content_is_same(false) { 25 } 26 27 std::string local_id; 28 ResourceEntry entry; 29 base::FilePath drive_file_path; 30 base::FilePath cache_file_path; 31 bool content_is_same; 32 }; 33 34 namespace { 35 36 // Gets locally stored information about the specified file. 37 FileError GetFileLocalState(internal::ResourceMetadata* metadata, 38 internal::FileCache* cache, 39 UpdateOperation::ContentCheckMode check, 40 UpdateOperation::LocalState* local_state) { 41 FileError error = metadata->GetResourceEntryById(local_state->local_id, 42 &local_state->entry); 43 if (error != FILE_ERROR_OK) 44 return error; 45 46 if (local_state->entry.file_info().is_directory()) 47 return FILE_ERROR_NOT_A_FILE; 48 49 local_state->drive_file_path = metadata->GetFilePath(local_state->local_id); 50 if (local_state->drive_file_path.empty()) 51 return FILE_ERROR_NOT_FOUND; 52 53 error = cache->GetFile(local_state->local_id, &local_state->cache_file_path); 54 if (error != FILE_ERROR_OK) 55 return error; 56 57 if (check == UpdateOperation::RUN_CONTENT_CHECK) { 58 const std::string& md5 = util::GetMd5Digest(local_state->cache_file_path); 59 local_state->content_is_same = 60 (md5 == local_state->entry.file_specific_info().md5()); 61 if (local_state->content_is_same) 62 cache->ClearDirty(local_state->local_id, md5); 63 } else { 64 local_state->content_is_same = false; 65 } 66 67 return FILE_ERROR_OK; 68 } 69 70 // Updates locally stored information about the specified file. 71 FileError UpdateFileLocalState( 72 internal::ResourceMetadata* metadata, 73 internal::FileCache* cache, 74 const std::string& local_id, 75 scoped_ptr<google_apis::ResourceEntry> resource_entry, 76 base::FilePath* drive_file_path) { 77 ResourceEntry entry; 78 std::string parent_resource_id; 79 if (!ConvertToResourceEntry(*resource_entry, &entry, &parent_resource_id)) 80 return FILE_ERROR_NOT_A_FILE; 81 82 std::string parent_local_id; 83 FileError error = metadata->GetIdByResourceId(parent_resource_id, 84 &parent_local_id); 85 if (error != FILE_ERROR_OK) 86 return error; 87 entry.set_local_id(local_id); 88 entry.set_parent_local_id(parent_local_id); 89 90 error = metadata->RefreshEntry(entry); 91 if (error != FILE_ERROR_OK) 92 return error; 93 94 *drive_file_path = metadata->GetFilePath(local_id); 95 if (drive_file_path->empty()) 96 return FILE_ERROR_NOT_FOUND; 97 98 // Clear the dirty bit if we have updated an existing file. 99 return cache->ClearDirty(local_id, entry.file_specific_info().md5()); 100 } 101 102 } // namespace 103 104 UpdateOperation::UpdateOperation( 105 base::SequencedTaskRunner* blocking_task_runner, 106 OperationObserver* observer, 107 JobScheduler* scheduler, 108 internal::ResourceMetadata* metadata, 109 internal::FileCache* cache) 110 : blocking_task_runner_(blocking_task_runner), 111 observer_(observer), 112 scheduler_(scheduler), 113 metadata_(metadata), 114 cache_(cache), 115 weak_ptr_factory_(this) { 116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 117 } 118 119 UpdateOperation::~UpdateOperation() { 120 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 121 } 122 123 void UpdateOperation::UpdateFileByLocalId( 124 const std::string& local_id, 125 const ClientContext& context, 126 ContentCheckMode check, 127 const FileOperationCallback& callback) { 128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 129 DCHECK(!callback.is_null()); 130 131 LocalState* local_state = new LocalState; 132 local_state->local_id = local_id; 133 base::PostTaskAndReplyWithResult( 134 blocking_task_runner_.get(), 135 FROM_HERE, 136 base::Bind(&GetFileLocalState, 137 metadata_, 138 cache_, 139 check, 140 local_state), 141 base::Bind(&UpdateOperation::UpdateFileAfterGetLocalState, 142 weak_ptr_factory_.GetWeakPtr(), 143 context, 144 callback, 145 base::Owned(local_state))); 146 } 147 148 void UpdateOperation::UpdateFileAfterGetLocalState( 149 const ClientContext& context, 150 const FileOperationCallback& callback, 151 const LocalState* local_state, 152 FileError error) { 153 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 154 DCHECK(!callback.is_null()); 155 156 if (error != FILE_ERROR_OK || local_state->content_is_same) { 157 callback.Run(error); 158 return; 159 } 160 161 scheduler_->UploadExistingFile( 162 local_state->entry.resource_id(), 163 local_state->drive_file_path, 164 local_state->cache_file_path, 165 local_state->entry.file_specific_info().content_mime_type(), 166 "", // etag 167 context, 168 base::Bind(&UpdateOperation::UpdateFileAfterUpload, 169 weak_ptr_factory_.GetWeakPtr(), 170 callback, 171 local_state->local_id)); 172 } 173 174 void UpdateOperation::UpdateFileAfterUpload( 175 const FileOperationCallback& callback, 176 const std::string& local_id, 177 google_apis::GDataErrorCode error, 178 scoped_ptr<google_apis::ResourceEntry> resource_entry) { 179 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 180 DCHECK(!callback.is_null()); 181 182 FileError drive_error = GDataToFileError(error); 183 if (drive_error != FILE_ERROR_OK) { 184 callback.Run(drive_error); 185 return; 186 } 187 188 base::FilePath* drive_file_path = new base::FilePath; 189 base::PostTaskAndReplyWithResult( 190 blocking_task_runner_.get(), 191 FROM_HERE, 192 base::Bind(&UpdateFileLocalState, 193 metadata_, 194 cache_, 195 local_id, 196 base::Passed(&resource_entry), 197 drive_file_path), 198 base::Bind(&UpdateOperation::UpdateFileAfterUpdateLocalState, 199 weak_ptr_factory_.GetWeakPtr(), 200 callback, 201 base::Owned(drive_file_path))); 202 } 203 204 void UpdateOperation::UpdateFileAfterUpdateLocalState( 205 const FileOperationCallback& callback, 206 const base::FilePath* drive_file_path, 207 FileError error) { 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 209 DCHECK(!callback.is_null()); 210 211 if (error != FILE_ERROR_OK) { 212 callback.Run(error); 213 return; 214 } 215 observer_->OnDirectoryChangedByOperation(drive_file_path->DirName()); 216 callback.Run(FILE_ERROR_OK); 217 } 218 219 } // namespace file_system 220 } // namespace drive 221