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.
5 #include "chrome/browser/chromeos/drive/sync/remove_performer.h"
7 #include "base/sequenced_task_runner.h"
8 #include "chrome/browser/chromeos/drive/file_system/operation_delegate.h"
9 #include "chrome/browser/chromeos/drive/sync/entry_revert_performer.h"
10 #include "components/drive/drive.pb.h"
11 #include "components/drive/drive_api_util.h"
12 #include "components/drive/file_system_core_util.h"
13 #include "components/drive/job_scheduler.h"
14 #include "components/drive/resource_entry_conversion.h"
15 #include "components/drive/resource_metadata.h"
16 #include "google_apis/drive/drive_api_parser.h"
23 // Updates local metadata and after remote unparenting.
24 FileError
UpdateLocalStateAfterUnparent(ResourceMetadata
* metadata
,
25 const std::string
& local_id
) {
27 FileError error
= metadata
->GetResourceEntryById(local_id
, &entry
);
28 if (error
!= FILE_ERROR_OK
)
30 entry
.set_parent_local_id(util::kDriveOtherDirLocalId
);
31 return metadata
->RefreshEntry(entry
);
34 // Utility function to run ResourceMetadata::RemoveEntry from UI thread.
35 void RemoveEntryOnUIThread(base::SequencedTaskRunner
* blocking_task_runner
,
36 ResourceMetadata
* metadata
,
37 const std::string
& local_id
,
38 const FileOperationCallback
& callback
) {
39 base::PostTaskAndReplyWithResult(
42 base::Bind(&ResourceMetadata::RemoveEntry
,
43 base::Unretained(metadata
), local_id
),
49 RemovePerformer::RemovePerformer(
50 base::SequencedTaskRunner
* blocking_task_runner
,
51 file_system::OperationDelegate
* delegate
,
52 JobScheduler
* scheduler
,
53 ResourceMetadata
* metadata
)
54 : blocking_task_runner_(blocking_task_runner
),
56 scheduler_(scheduler
),
58 entry_revert_performer_(new EntryRevertPerformer(blocking_task_runner
,
62 weak_ptr_factory_(this) {
65 RemovePerformer::~RemovePerformer() {
66 DCHECK(thread_checker_
.CalledOnValidThread());
69 // Returns |entry| corresponding to |local_id|.
70 // Adding to that, removes the entry when it does not exist on the server.
71 FileError
TryToRemoveLocally(ResourceMetadata
* metadata
,
72 const std::string
& local_id
,
73 ResourceEntry
* entry
) {
74 FileError error
= metadata
->GetResourceEntryById(local_id
, entry
);
75 if (error
!= FILE_ERROR_OK
|| !entry
->resource_id().empty())
77 return metadata
->RemoveEntry(local_id
);
80 void RemovePerformer::Remove(const std::string
& local_id
,
81 const ClientContext
& context
,
82 const FileOperationCallback
& callback
) {
83 DCHECK(thread_checker_
.CalledOnValidThread());
84 DCHECK(!callback
.is_null());
86 ResourceEntry
* entry
= new ResourceEntry
;
87 base::PostTaskAndReplyWithResult(
88 blocking_task_runner_
.get(),
90 base::Bind(&TryToRemoveLocally
, metadata_
, local_id
, entry
),
91 base::Bind(&RemovePerformer::RemoveAfterGetResourceEntry
,
92 weak_ptr_factory_
.GetWeakPtr(),
98 void RemovePerformer::RemoveAfterGetResourceEntry(
99 const ClientContext
& context
,
100 const FileOperationCallback
& callback
,
101 const ResourceEntry
* entry
,
103 DCHECK(thread_checker_
.CalledOnValidThread());
104 DCHECK(!callback
.is_null());
106 if (error
!= FILE_ERROR_OK
|| entry
->resource_id().empty()) {
111 // To match with the behavior of drive.google.com:
112 // Removal of shared entries under MyDrive is just removing from the parent.
113 // The entry will stay in shared-with-me (in other words, in "drive/other".)
115 // TODO(kinaba): to be more precise, we might be better to branch by whether
116 // or not the current account is an owner of the file. The code below is
117 // written under the assumption that |shared_with_me| coincides with that.
118 if (entry
->shared_with_me()) {
119 UnparentResource(context
, callback
, entry
->resource_id(),
122 // Otherwise try sending the entry to trash.
123 TrashResource(context
, callback
, entry
->resource_id(), entry
->local_id());
127 void RemovePerformer::TrashResource(const ClientContext
& context
,
128 const FileOperationCallback
& callback
,
129 const std::string
& resource_id
,
130 const std::string
& local_id
) {
131 DCHECK(thread_checker_
.CalledOnValidThread());
132 DCHECK(!callback
.is_null());
134 scheduler_
->TrashResource(
137 base::Bind(&RemovePerformer::TrashResourceAfterUpdateRemoteState
,
138 weak_ptr_factory_
.GetWeakPtr(), context
, callback
, local_id
));
141 void RemovePerformer::TrashResourceAfterUpdateRemoteState(
142 const ClientContext
& context
,
143 const FileOperationCallback
& callback
,
144 const std::string
& local_id
,
145 google_apis::DriveApiErrorCode status
) {
146 DCHECK(thread_checker_
.CalledOnValidThread());
147 DCHECK(!callback
.is_null());
149 if (status
== google_apis::HTTP_FORBIDDEN
) {
150 // Editing this entry is not allowed, revert local changes.
151 entry_revert_performer_
->RevertEntry(local_id
, context
, callback
);
152 delegate_
->OnDriveSyncError(
153 file_system::DRIVE_SYNC_ERROR_DELETE_WITHOUT_PERMISSION
, local_id
);
157 FileError error
= GDataToFileError(status
);
158 if (error
== FILE_ERROR_NOT_FOUND
) { // Remove local entry when not found.
159 RemoveEntryOnUIThread(blocking_task_runner_
.get(), metadata_
, local_id
,
164 // Now we're done. If the entry is trashed on the server, it'll be also
165 // deleted locally on the next update.
169 void RemovePerformer::UnparentResource(const ClientContext
& context
,
170 const FileOperationCallback
& callback
,
171 const std::string
& resource_id
,
172 const std::string
& local_id
) {
173 DCHECK(thread_checker_
.CalledOnValidThread());
174 DCHECK(!callback
.is_null());
176 scheduler_
->GetFileResource(
179 base::Bind(&RemovePerformer::UnparentResourceAfterGetFileResource
,
180 weak_ptr_factory_
.GetWeakPtr(), context
, callback
, local_id
));
183 void RemovePerformer::UnparentResourceAfterGetFileResource(
184 const ClientContext
& context
,
185 const FileOperationCallback
& callback
,
186 const std::string
& local_id
,
187 google_apis::DriveApiErrorCode status
,
188 scoped_ptr
<google_apis::FileResource
> file_resource
) {
189 DCHECK(thread_checker_
.CalledOnValidThread());
190 DCHECK(!callback
.is_null());
192 FileError error
= GDataToFileError(status
);
193 if (error
== FILE_ERROR_NOT_FOUND
) { // Remove local entry when not found.
194 RemoveEntryOnUIThread(blocking_task_runner_
.get(), metadata_
, local_id
,
199 if (error
!= FILE_ERROR_OK
) {
205 std::string parent_resource_id
;
206 if (!ConvertFileResourceToResourceEntry(*file_resource
, &entry
,
207 &parent_resource_id
)) {
208 callback
.Run(FILE_ERROR_NOT_A_FILE
);
212 if (!entry
.shared_with_me()) {
213 // shared_with_me() has changed on the server.
214 UnparentResourceAfterUpdateRemoteState(callback
, local_id
,
215 google_apis::HTTP_CONFLICT
);
219 if (parent_resource_id
.empty()) {
220 // This entry is unparented already.
221 UnparentResourceAfterUpdateRemoteState(callback
, local_id
,
222 google_apis::HTTP_NO_CONTENT
);
226 scheduler_
->RemoveResourceFromDirectory(
230 base::Bind(&RemovePerformer::UnparentResourceAfterUpdateRemoteState
,
231 weak_ptr_factory_
.GetWeakPtr(), callback
, local_id
));
234 void RemovePerformer::UnparentResourceAfterUpdateRemoteState(
235 const FileOperationCallback
& callback
,
236 const std::string
& local_id
,
237 google_apis::DriveApiErrorCode status
) {
238 DCHECK(thread_checker_
.CalledOnValidThread());
239 DCHECK(!callback
.is_null());
241 FileError error
= GDataToFileError(status
);
242 if (error
!= FILE_ERROR_OK
) {
247 base::PostTaskAndReplyWithResult(
248 blocking_task_runner_
.get(),
250 base::Bind(&UpdateLocalStateAfterUnparent
, metadata_
, local_id
),
254 } // namespace internal