Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / chromeos / drive / file_system / create_directory_operation.cc
blob9f1fce1e19ed1e08bba374cc5b20118c4bdd5788
1 // Copyright (c) 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/file_system/create_directory_operation.h"
7 #include "chrome/browser/chromeos/drive/drive.pb.h"
8 #include "chrome/browser/chromeos/drive/file_system/operation_observer.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_entry_conversion.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "google_apis/drive/gdata_errorcode.h"
14 #include "google_apis/drive/gdata_wapi_parser.h"
16 using content::BrowserThread;
18 namespace drive {
19 namespace file_system {
21 namespace {
23 // Part of CreateDirectoryRecursively(). Adds an |entry| for new directory
24 // to |metadata|, and return the status. If succeeded, |file_path| will store
25 // the path to the result file.
26 FileError UpdateLocalStateForCreateDirectoryRecursively(
27 internal::ResourceMetadata* metadata,
28 scoped_ptr<google_apis::ResourceEntry> resource_entry,
29 base::FilePath* file_path) {
30 DCHECK(metadata);
31 DCHECK(file_path);
33 ResourceEntry entry;
34 std::string parent_resource_id;
35 if (!ConvertToResourceEntry(*resource_entry, &entry, &parent_resource_id) ||
36 parent_resource_id.empty())
37 return FILE_ERROR_NOT_A_FILE;
39 std::string parent_local_id;
40 FileError result = metadata->GetIdByResourceId(parent_resource_id,
41 &parent_local_id);
42 if (result != FILE_ERROR_OK)
43 return result;
44 entry.set_parent_local_id(parent_local_id);
46 std::string local_id;
47 result = metadata->AddEntry(entry, &local_id);
48 // Depending on timing, a metadata may be updated by change list already.
49 // So, FILE_ERROR_EXISTS is not an error.
50 if (result == FILE_ERROR_EXISTS)
51 result = metadata->GetIdByResourceId(entry.resource_id(), &local_id);
53 if (result == FILE_ERROR_OK)
54 *file_path = metadata->GetFilePath(local_id);
56 return result;
59 } // namespace
61 CreateDirectoryOperation::CreateDirectoryOperation(
62 base::SequencedTaskRunner* blocking_task_runner,
63 OperationObserver* observer,
64 JobScheduler* scheduler,
65 internal::ResourceMetadata* metadata)
66 : blocking_task_runner_(blocking_task_runner),
67 observer_(observer),
68 scheduler_(scheduler),
69 metadata_(metadata),
70 weak_ptr_factory_(this) {
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74 CreateDirectoryOperation::~CreateDirectoryOperation() {
75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
78 void CreateDirectoryOperation::CreateDirectory(
79 const base::FilePath& directory_path,
80 bool is_exclusive,
81 bool is_recursive,
82 const FileOperationCallback& callback) {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
84 DCHECK(!callback.is_null());
86 ResourceEntry* entry = new ResourceEntry;
87 base::PostTaskAndReplyWithResult(
88 blocking_task_runner_.get(),
89 FROM_HERE,
90 base::Bind(&CreateDirectoryOperation::GetExistingDeepestDirectory,
91 metadata_,
92 directory_path,
93 entry),
94 base::Bind(&CreateDirectoryOperation::
95 CreateDirectoryAfterGetExistingDeepestDirectory,
96 weak_ptr_factory_.GetWeakPtr(),
97 directory_path,
98 is_exclusive,
99 is_recursive,
100 callback,
101 base::Owned(entry)));
104 // static
105 base::FilePath CreateDirectoryOperation::GetExistingDeepestDirectory(
106 internal::ResourceMetadata* metadata,
107 const base::FilePath& directory_path,
108 ResourceEntry* entry) {
109 DCHECK(metadata);
110 DCHECK(entry);
112 std::vector<base::FilePath::StringType> components;
113 directory_path.GetComponents(&components);
115 if (components.empty() || components[0] != util::kDriveGrandRootDirName)
116 return base::FilePath();
118 base::FilePath result_path(components[0]);
119 std::string local_id = util::kDriveGrandRootLocalId;
120 for (size_t i = 1; i < components.size(); ++i) {
121 std::string child_local_id = metadata->GetChildId(local_id, components[i]);
122 if (child_local_id.empty())
123 break;
124 result_path = result_path.Append(components[i]);
125 local_id = child_local_id;
128 FileError error = metadata->GetResourceEntryById(local_id, entry);
129 DCHECK_EQ(FILE_ERROR_OK, error);
131 if (!entry->file_info().is_directory())
132 return base::FilePath();
134 return result_path;
137 void CreateDirectoryOperation::CreateDirectoryAfterGetExistingDeepestDirectory(
138 const base::FilePath& directory_path,
139 bool is_exclusive,
140 bool is_recursive,
141 const FileOperationCallback& callback,
142 ResourceEntry* existing_deepest_directory_entry,
143 const base::FilePath& existing_deepest_directory_path) {
144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
145 DCHECK(!callback.is_null());
146 DCHECK(existing_deepest_directory_entry);
148 if (existing_deepest_directory_path.empty()) {
149 callback.Run(FILE_ERROR_NOT_FOUND);
150 return;
153 if (directory_path == existing_deepest_directory_path) {
154 callback.Run(is_exclusive ? FILE_ERROR_EXISTS : FILE_ERROR_OK);
155 return;
158 // If it is not recursive creation, the found directory must be the direct
159 // parent of |directory_path| to ensure creating exact one directory.
160 if (!is_recursive &&
161 existing_deepest_directory_path != directory_path.DirName()) {
162 callback.Run(FILE_ERROR_NOT_FOUND);
163 return;
166 // Create directories under the found directory.
167 base::FilePath remaining_path;
168 existing_deepest_directory_path.AppendRelativePath(
169 directory_path, &remaining_path);
170 CreateDirectoryRecursively(existing_deepest_directory_entry->resource_id(),
171 remaining_path, callback);
174 void CreateDirectoryOperation::CreateDirectoryRecursively(
175 const std::string& parent_resource_id,
176 const base::FilePath& relative_file_path,
177 const FileOperationCallback& callback) {
178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
179 DCHECK(!callback.is_null());
181 // Split the first component and remaining ones of |relative_file_path|.
182 std::vector<base::FilePath::StringType> components;
183 relative_file_path.GetComponents(&components);
184 DCHECK(!components.empty());
185 base::FilePath title(components[0]);
186 base::FilePath remaining_path;
187 title.AppendRelativePath(relative_file_path, &remaining_path);
189 scheduler_->AddNewDirectory(
190 parent_resource_id,
191 title.AsUTF8Unsafe(),
192 base::Bind(&CreateDirectoryOperation
193 ::CreateDirectoryRecursivelyAfterAddNewDirectory,
194 weak_ptr_factory_.GetWeakPtr(), remaining_path, callback));
197 void CreateDirectoryOperation::CreateDirectoryRecursivelyAfterAddNewDirectory(
198 const base::FilePath& remaining_path,
199 const FileOperationCallback& callback,
200 google_apis::GDataErrorCode gdata_error,
201 scoped_ptr<google_apis::ResourceEntry> resource_entry) {
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
203 DCHECK(!callback.is_null());
205 FileError error = GDataToFileError(gdata_error);
206 if (error != FILE_ERROR_OK) {
207 callback.Run(error);
208 return;
210 DCHECK(resource_entry);
211 const std::string& resource_id = resource_entry->resource_id();
213 // Note that the created directory may be renamed inside
214 // ResourceMetadata::AddEntry due to name confliction.
215 // What we actually need here is the new created path (not the path we try
216 // to create).
217 base::FilePath* file_path = new base::FilePath;
218 base::PostTaskAndReplyWithResult(
219 blocking_task_runner_.get(),
220 FROM_HERE,
221 base::Bind(&UpdateLocalStateForCreateDirectoryRecursively,
222 metadata_,
223 base::Passed(&resource_entry),
224 file_path),
225 base::Bind(&CreateDirectoryOperation::
226 CreateDirectoryRecursivelyAfterUpdateLocalState,
227 weak_ptr_factory_.GetWeakPtr(),
228 resource_id,
229 remaining_path,
230 callback,
231 base::Owned(file_path)));
234 void CreateDirectoryOperation::CreateDirectoryRecursivelyAfterUpdateLocalState(
235 const std::string& resource_id,
236 const base::FilePath& remaining_path,
237 const FileOperationCallback& callback,
238 base::FilePath* file_path,
239 FileError error) {
240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
241 DCHECK(!callback.is_null());
243 if (error != FILE_ERROR_OK) {
244 callback.Run(error);
245 return;
248 observer_->OnDirectoryChangedByOperation(file_path->DirName());
250 if (remaining_path.empty()) {
251 // All directories are created successfully.
252 callback.Run(FILE_ERROR_OK);
253 return;
256 // Create descendant directories.
257 CreateDirectoryRecursively(resource_id, remaining_path, callback);
260 } // namespace file_system
261 } // namespace drive