Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / sync / entry_update_performer.cc
1 // Copyright 2013 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/sync/entry_update_performer.h"
6
7 #include "chrome/browser/chromeos/drive/drive.pb.h"
8 #include "chrome/browser/chromeos/drive/file_cache.h"
9 #include "chrome/browser/chromeos/drive/file_system_util.h"
10 #include "chrome/browser/chromeos/drive/job_scheduler.h"
11 #include "chrome/browser/chromeos/drive/resource_metadata.h"
12 #include "chrome/browser/chromeos/drive/sync/entry_revert_performer.h"
13 #include "chrome/browser/chromeos/drive/sync/remove_performer.h"
14 #include "content/public/browser/browser_thread.h"
15
16 using content::BrowserThread;
17
18 namespace drive {
19 namespace internal {
20
21 struct EntryUpdatePerformer::LocalState {
22   LocalState() : should_content_update(false) {
23   }
24
25   ResourceEntry entry;
26   ResourceEntry parent_entry;
27   base::FilePath drive_file_path;
28   base::FilePath cache_file_path;
29   bool should_content_update;
30 };
31
32 namespace {
33
34 // Looks up ResourceEntry for source entry and its parent.
35 FileError PrepareUpdate(ResourceMetadata* metadata,
36                         FileCache* cache,
37                         const std::string& local_id,
38                         EntryUpdatePerformer::LocalState* local_state) {
39   FileError error = metadata->GetResourceEntryById(local_id,
40                                                    &local_state->entry);
41   if (error != FILE_ERROR_OK)
42     return error;
43
44   error = metadata->GetResourceEntryById(local_state->entry.parent_local_id(),
45                                          &local_state->parent_entry);
46   if (error != FILE_ERROR_OK)
47     return error;
48
49   local_state->drive_file_path = metadata->GetFilePath(local_id);
50   if (local_state->drive_file_path.empty())
51     return FILE_ERROR_NOT_FOUND;
52
53   // Check if content update is needed or not.
54   FileCacheEntry cache_entry;
55   if (cache->GetCacheEntry(local_id, &cache_entry) &&
56       cache_entry.is_dirty() &&
57       !cache->IsOpenedForWrite(local_id)) {
58     // Update cache entry's MD5 if needed.
59     if (cache_entry.md5().empty()) {
60       error = cache->UpdateMd5(local_id);
61       if (error != FILE_ERROR_OK)
62         return error;
63       if (!cache->GetCacheEntry(local_id, &cache_entry))
64         return FILE_ERROR_NOT_FOUND;
65     }
66
67     if (cache_entry.md5() == local_state->entry.file_specific_info().md5()) {
68       error = cache->ClearDirty(local_id);
69       if (error != FILE_ERROR_OK)
70         return error;
71     } else {
72       error = cache->GetFile(local_id, &local_state->cache_file_path);
73       if (error != FILE_ERROR_OK)
74         return error;
75
76       local_state->should_content_update = true;
77     }
78   }
79
80   // Update metadata_edit_state.
81   switch (local_state->entry.metadata_edit_state()) {
82     case ResourceEntry::CLEAN:  // Nothing to do.
83     case ResourceEntry::SYNCING:  // Error during the last update. Go ahead.
84       break;
85
86     case ResourceEntry::DIRTY:
87       local_state->entry.set_metadata_edit_state(ResourceEntry::SYNCING);
88       error = metadata->RefreshEntry(local_state->entry);
89       if (error != FILE_ERROR_OK)
90         return error;
91       break;
92   }
93   return FILE_ERROR_OK;
94 }
95
96 FileError FinishUpdate(ResourceMetadata* metadata,
97                        FileCache* cache,
98                        const std::string& local_id,
99                        scoped_ptr<google_apis::ResourceEntry> resource_entry) {
100   ResourceEntry entry;
101   FileError error = metadata->GetResourceEntryById(local_id, &entry);
102   if (error != FILE_ERROR_OK)
103     return error;
104
105   // Update metadata_edit_state and MD5.
106   switch (entry.metadata_edit_state()) {
107     case ResourceEntry::CLEAN:  // Nothing to do.
108     case ResourceEntry::DIRTY:  // Entry was edited again during the update.
109       break;
110
111     case ResourceEntry::SYNCING:
112       entry.set_metadata_edit_state(ResourceEntry::CLEAN);
113       break;
114   }
115   if (!entry.file_info().is_directory())
116     entry.mutable_file_specific_info()->set_md5(resource_entry->file_md5());
117   error = metadata->RefreshEntry(entry);
118   if (error != FILE_ERROR_OK)
119     return error;
120
121   // Clear dirty bit unless the file has been edited during update.
122   FileCacheEntry cache_entry;
123   if (cache->GetCacheEntry(local_id, &cache_entry) &&
124       cache_entry.md5() == entry.file_specific_info().md5()) {
125     error = cache->ClearDirty(local_id);
126     if (error != FILE_ERROR_OK)
127       return error;
128   }
129   return FILE_ERROR_OK;
130 }
131
132 }  // namespace
133
134 EntryUpdatePerformer::EntryUpdatePerformer(
135     base::SequencedTaskRunner* blocking_task_runner,
136     file_system::OperationObserver* observer,
137     JobScheduler* scheduler,
138     ResourceMetadata* metadata,
139     FileCache* cache)
140     : blocking_task_runner_(blocking_task_runner),
141       scheduler_(scheduler),
142       metadata_(metadata),
143       cache_(cache),
144       remove_performer_(new RemovePerformer(blocking_task_runner,
145                                             observer,
146                                             scheduler,
147                                             metadata)),
148       entry_revert_performer_(new EntryRevertPerformer(blocking_task_runner,
149                                                        observer,
150                                                        scheduler,
151                                                        metadata)),
152       weak_ptr_factory_(this) {
153   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
154 }
155
156 EntryUpdatePerformer::~EntryUpdatePerformer() {
157   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
158 }
159
160 void EntryUpdatePerformer::UpdateEntry(const std::string& local_id,
161                                        const ClientContext& context,
162                                        const FileOperationCallback& callback) {
163   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
164   DCHECK(!callback.is_null());
165
166   scoped_ptr<LocalState> local_state(new LocalState);
167   LocalState* local_state_ptr = local_state.get();
168   base::PostTaskAndReplyWithResult(
169       blocking_task_runner_.get(),
170       FROM_HERE,
171       base::Bind(&PrepareUpdate, metadata_, cache_, local_id, local_state_ptr),
172       base::Bind(&EntryUpdatePerformer::UpdateEntryAfterPrepare,
173                  weak_ptr_factory_.GetWeakPtr(), context, callback,
174                  base::Passed(&local_state)));
175 }
176
177 void EntryUpdatePerformer::UpdateEntryAfterPrepare(
178     const ClientContext& context,
179     const FileOperationCallback& callback,
180     scoped_ptr<LocalState> local_state,
181     FileError error) {
182   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
183   DCHECK(!callback.is_null());
184
185   if (error != FILE_ERROR_OK) {
186     callback.Run(error);
187     return;
188   }
189
190   // Trashed entry should be removed.
191   if (local_state->entry.parent_local_id() == util::kDriveTrashDirLocalId) {
192     remove_performer_->Remove(local_state->entry.local_id(), context, callback);
193     return;
194   }
195
196   base::Time last_modified = base::Time::FromInternalValue(
197       local_state->entry.file_info().last_modified());
198   base::Time last_accessed = base::Time::FromInternalValue(
199       local_state->entry.file_info().last_accessed());
200
201   // Perform content update.
202   if (local_state->should_content_update) {
203     drive::DriveUploader::UploadExistingFileOptions options;
204     options.title = local_state->entry.title();
205     options.parent_resource_id = local_state->parent_entry.resource_id();
206     options.modified_date = last_modified;
207     options.last_viewed_by_me_date = last_accessed;
208     scheduler_->UploadExistingFile(
209         local_state->entry.resource_id(),
210         local_state->drive_file_path,
211         local_state->cache_file_path,
212         local_state->entry.file_specific_info().content_mime_type(),
213         options,
214         context,
215         base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource,
216                    weak_ptr_factory_.GetWeakPtr(),
217                    context,
218                    callback,
219                    local_state->entry.local_id()));
220     return;
221   }
222
223   // No need to perform update.
224   if (local_state->entry.metadata_edit_state() == ResourceEntry::CLEAN) {
225     callback.Run(FILE_ERROR_OK);
226     return;
227   }
228
229   // Perform metadata update.
230   scheduler_->UpdateResource(
231       local_state->entry.resource_id(), local_state->parent_entry.resource_id(),
232       local_state->entry.title(), last_modified, last_accessed,
233       context,
234       base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource,
235                  weak_ptr_factory_.GetWeakPtr(),
236                  context, callback, local_state->entry.local_id()));
237 }
238
239 void EntryUpdatePerformer::UpdateEntryAfterUpdateResource(
240     const ClientContext& context,
241     const FileOperationCallback& callback,
242     const std::string& local_id,
243     google_apis::GDataErrorCode status,
244     scoped_ptr<google_apis::ResourceEntry> resource_entry) {
245   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
246
247   if (status == google_apis::HTTP_FORBIDDEN) {
248     // Editing this entry is not allowed, revert local changes.
249     entry_revert_performer_->RevertEntry(local_id, context, callback);
250     return;
251   }
252
253   FileError error = GDataToFileError(status);
254   if (error != FILE_ERROR_OK) {
255     callback.Run(error);
256     return;
257   }
258
259   base::PostTaskAndReplyWithResult(
260       blocking_task_runner_.get(),
261       FROM_HERE,
262       base::Bind(&FinishUpdate,
263                  metadata_, cache_, local_id, base::Passed(&resource_entry)),
264       callback);
265 }
266
267 }  // namespace internal
268 }  // namespace drive