- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / drive / file_system / remove_operation.cc
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/remove_operation.h"
6
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"
14
15 using content::BrowserThread;
16
17 namespace drive {
18 namespace file_system {
19
20 namespace {
21
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,
29                           bool is_recursive,
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)
35     return error;
36
37   error = metadata->GetResourceEntryById(*local_id, entry);
38   if (error != FILE_ERROR_OK)
39     return error;
40
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)
46       return error;
47     if (!entries.empty())
48       return FILE_ERROR_NOT_EMPTY;
49   }
50
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 = "";
55   } else {
56     ResourceEntry parent_entry;
57     error = metadata->GetResourceEntryById(entry->parent_local_id(),
58                                            &parent_entry);
59     if (error != FILE_ERROR_OK)
60         return error;
61     *parent_resource_id = parent_entry.resource_id();
62   }
63
64   return FILE_ERROR_OK;
65 }
66
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)
75     return error;
76
77   error = cache->Remove(local_id);
78   DLOG_IF(ERROR, error != FILE_ERROR_OK) << "Failed to remove: " << local_id;
79
80   return FILE_ERROR_OK;
81 }
82
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();
89
90   ResourceEntry entry;
91   FileError error = metadata->GetResourceEntryById(local_id, &entry);
92   if (error != FILE_ERROR_OK)
93     return error;
94   entry.set_parent_local_id(util::kDriveOtherDirSpecialResourceId);
95   return metadata->RefreshEntry(entry);
96 }
97
98 }  // namespace
99
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),
107       observer_(observer),
108       scheduler_(scheduler),
109       metadata_(metadata),
110       cache_(cache),
111       weak_ptr_factory_(this) {
112   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
113 }
114
115 RemoveOperation::~RemoveOperation() {
116   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
117 }
118
119 void RemoveOperation::Remove(const base::FilePath& path,
120                              bool is_recursive,
121                              const FileOperationCallback& callback) {
122   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
123   DCHECK(!callback.is_null());
124
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(),
130       FROM_HERE,
131       base::Bind(&CheckLocalState,
132                  metadata_,
133                  path,
134                  is_recursive,
135                  parent_resource_id,
136                  local_id,
137                  entry),
138       base::Bind(&RemoveOperation::RemoveAfterCheckLocalState,
139                  weak_ptr_factory_.GetWeakPtr(),
140                  callback,
141                  base::Owned(parent_resource_id),
142                  base::Owned(local_id),
143                  base::Owned(entry)));
144 }
145
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,
151     FileError error) {
152   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
153   DCHECK(!callback.is_null());
154
155   if (error != FILE_ERROR_OK) {
156     callback.Run(error);
157     return;
158   }
159
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".)
163   //
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(
169         *parent_resource_id,
170         entry->resource_id(),
171         base::Bind(&RemoveOperation::RemoveAfterUpdateRemoteState,
172                    weak_ptr_factory_.GetWeakPtr(),
173                    callback,
174                    base::Bind(&UpdateLocalStateAfterUnparent,
175                               metadata_,
176                               *local_id)));
177   } else {
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(),
183                    callback,
184                    base::Bind(&UpdateLocalStateAfterDelete,
185                               metadata_,
186                               cache_,
187                               *local_id)));
188   }
189 }
190
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());
197
198   FileError error = GDataToFileError(status);
199   if (error != FILE_ERROR_OK) {
200     callback.Run(error);
201     return;
202   }
203
204   base::FilePath* changed_directory_path = new base::FilePath;
205   base::PostTaskAndReplyWithResult(
206       blocking_task_runner_.get(),
207       FROM_HERE,
208       base::Bind(local_update_task, changed_directory_path),
209       base::Bind(&RemoveOperation::RemoveAfterUpdateLocalState,
210                  weak_ptr_factory_.GetWeakPtr(),
211                  callback,
212                  base::Owned(changed_directory_path)));
213 }
214
215 void RemoveOperation::RemoveAfterUpdateLocalState(
216     const FileOperationCallback& callback,
217     const base::FilePath* changed_directory_path,
218     FileError error) {
219   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
220   DCHECK(!callback.is_null());
221
222   if (error == FILE_ERROR_OK)
223     observer_->OnDirectoryChangedByOperation(*changed_directory_path);
224
225   callback.Run(error);
226 }
227
228 }  // namespace file_system
229 }  // namespace drive