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.
5 #include "chrome/browser/chromeos/drive/file_system/remove_operation.h"
7 #include "base/sequenced_task_runner.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 "content/public/browser/browser_thread.h"
15 using content::BrowserThread;
18 namespace file_system {
22 // Checks local metadata state before requesting remote delete.
23 // |parent_resource_id| is set to the resource ID of the parent directory of
24 // |path|. If it is a special folder like drive/other, empty string is set.
25 // |local_id| is set to the local ID of the entry located at |path|.
26 // |entry| is the resource entry for the |path|.
27 FileError CheckLocalState(internal::ResourceMetadata* metadata,
28 const base::FilePath& path,
30 std::string* parent_resource_id,
31 std::string* local_id,
32 ResourceEntry* entry) {
33 FileError error = metadata->GetIdByPath(path, local_id);
34 if (error != FILE_ERROR_OK)
37 error = metadata->GetResourceEntryById(*local_id, entry);
38 if (error != FILE_ERROR_OK)
41 if (entry->file_info().is_directory() && !is_recursive) {
42 // Check emptiness of the directory.
43 ResourceEntryVector entries;
44 error = metadata->ReadDirectoryByPath(path, &entries);
45 if (error != FILE_ERROR_OK)
48 return FILE_ERROR_NOT_EMPTY;
51 // Get the resource_id of the parent folder. If it is a special folder that
52 // does not have the server side ID, returns an empty string (not an error).
53 if (util::IsSpecialResourceId(entry->parent_local_id())) {
54 *parent_resource_id = "";
56 ResourceEntry parent_entry;
57 error = metadata->GetResourceEntryById(entry->parent_local_id(),
59 if (error != FILE_ERROR_OK)
61 *parent_resource_id = parent_entry.resource_id();
67 // Updates local metadata and cache state after remote delete.
68 FileError UpdateLocalStateAfterDelete(internal::ResourceMetadata* metadata,
69 internal::FileCache* cache,
70 const std::string& local_id,
71 base::FilePath* changed_directory_path) {
72 *changed_directory_path = metadata->GetFilePath(local_id).DirName();
73 FileError error = metadata->RemoveEntry(local_id);
74 if (error != FILE_ERROR_OK)
77 error = cache->Remove(local_id);
78 DLOG_IF(ERROR, error != FILE_ERROR_OK) << "Failed to remove: " << local_id;
83 // Updates local metadata and after remote unparenting.
84 FileError UpdateLocalStateAfterUnparent(
85 internal::ResourceMetadata* metadata,
86 const std::string& local_id,
87 base::FilePath* changed_directory_path) {
88 *changed_directory_path = metadata->GetFilePath(local_id).DirName();
91 FileError error = metadata->GetResourceEntryById(local_id, &entry);
92 if (error != FILE_ERROR_OK)
94 entry.set_parent_local_id(util::kDriveOtherDirSpecialResourceId);
95 return metadata->RefreshEntry(entry);
100 RemoveOperation::RemoveOperation(
101 base::SequencedTaskRunner* blocking_task_runner,
102 OperationObserver* observer,
103 JobScheduler* scheduler,
104 internal::ResourceMetadata* metadata,
105 internal::FileCache* cache)
106 : blocking_task_runner_(blocking_task_runner),
108 scheduler_(scheduler),
111 weak_ptr_factory_(this) {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
115 RemoveOperation::~RemoveOperation() {
116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
119 void RemoveOperation::Remove(const base::FilePath& path,
121 const FileOperationCallback& callback) {
122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
123 DCHECK(!callback.is_null());
125 std::string* parent_resource_id = new std::string;
126 std::string* local_id = new std::string;
127 ResourceEntry* entry = new ResourceEntry;
128 base::PostTaskAndReplyWithResult(
129 blocking_task_runner_.get(),
131 base::Bind(&CheckLocalState,
138 base::Bind(&RemoveOperation::RemoveAfterCheckLocalState,
139 weak_ptr_factory_.GetWeakPtr(),
141 base::Owned(parent_resource_id),
142 base::Owned(local_id),
143 base::Owned(entry)));
146 void RemoveOperation::RemoveAfterCheckLocalState(
147 const FileOperationCallback& callback,
148 const std::string* parent_resource_id,
149 const std::string* local_id,
150 const ResourceEntry* entry,
152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
153 DCHECK(!callback.is_null());
155 if (error != FILE_ERROR_OK) {
160 // To match with the behavior of drive.google.com:
161 // Removal of shared entries under MyDrive is just removing from the parent.
162 // The entry will stay in shared-with-me (in other words, in "drive/other".)
164 // TODO(kinaba): to be more precise, we might be better to branch by whether
165 // or not the current account is an owner of the file. The code below is
166 // written under the assumption that |shared_with_me| coincides with that.
167 if (entry->shared_with_me() && !parent_resource_id->empty()) {
168 scheduler_->RemoveResourceFromDirectory(
170 entry->resource_id(),
171 base::Bind(&RemoveOperation::RemoveAfterUpdateRemoteState,
172 weak_ptr_factory_.GetWeakPtr(),
174 base::Bind(&UpdateLocalStateAfterUnparent,
178 // Otherwise try sending the entry to trash.
179 scheduler_->DeleteResource(
180 entry->resource_id(),
181 base::Bind(&RemoveOperation::RemoveAfterUpdateRemoteState,
182 weak_ptr_factory_.GetWeakPtr(),
184 base::Bind(&UpdateLocalStateAfterDelete,
191 void RemoveOperation::RemoveAfterUpdateRemoteState(
192 const FileOperationCallback& callback,
193 const base::Callback<FileError(base::FilePath*)>& local_update_task,
194 google_apis::GDataErrorCode status) {
195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
196 DCHECK(!callback.is_null());
198 FileError error = GDataToFileError(status);
199 if (error != FILE_ERROR_OK) {
204 base::FilePath* changed_directory_path = new base::FilePath;
205 base::PostTaskAndReplyWithResult(
206 blocking_task_runner_.get(),
208 base::Bind(local_update_task, changed_directory_path),
209 base::Bind(&RemoveOperation::RemoveAfterUpdateLocalState,
210 weak_ptr_factory_.GetWeakPtr(),
212 base::Owned(changed_directory_path)));
215 void RemoveOperation::RemoveAfterUpdateLocalState(
216 const FileOperationCallback& callback,
217 const base::FilePath* changed_directory_path,
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
220 DCHECK(!callback.is_null());
222 if (error == FILE_ERROR_OK)
223 observer_->OnDirectoryChangedByOperation(*changed_directory_path);
228 } // namespace file_system