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/extensions/api/sync_file_system/sync_file_system_api.h"
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/strings/stringprintf.h"
13 #include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h"
14 #include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/sync_file_system/sync_file_status.h"
17 #include "chrome/browser/sync_file_system/sync_file_system_service.h"
18 #include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
19 #include "chrome/common/extensions/api/sync_file_system.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/storage_partition.h"
23 #include "content/public/common/content_client.h"
24 #include "storage/browser/fileapi/file_system_context.h"
25 #include "storage/browser/fileapi/file_system_url.h"
26 #include "storage/browser/quota/quota_manager.h"
27 #include "storage/common/fileapi/file_system_types.h"
28 #include "storage/common/fileapi/file_system_util.h"
30 using content::BrowserContext;
31 using content::BrowserThread;
32 using sync_file_system::ConflictResolutionPolicy;
33 using sync_file_system::SyncFileStatus;
34 using sync_file_system::SyncFileSystemServiceFactory;
35 using sync_file_system::SyncStatusCode;
37 namespace extensions {
42 const char kErrorMessage[] = "%s (error code: %d).";
43 const char kUnsupportedConflictResolutionPolicy[] =
44 "Policy %s is not supported.";
46 sync_file_system::SyncFileSystemService* GetSyncFileSystemService(
48 sync_file_system::SyncFileSystemService* service =
49 SyncFileSystemServiceFactory::GetForProfile(profile);
51 ExtensionSyncEventObserver* observer =
52 ExtensionSyncEventObserver::GetFactoryInstance()->Get(profile);
54 observer->InitializeForService(service);
58 std::string ErrorToString(SyncStatusCode code) {
59 return base::StringPrintf(
61 sync_file_system::SyncStatusCodeToString(code),
62 static_cast<int>(code));
67 bool SyncFileSystemDeleteFileSystemFunction::RunAsync() {
69 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
71 scoped_refptr<storage::FileSystemContext> file_system_context =
72 BrowserContext::GetStoragePartition(GetProfile(),
73 render_view_host()->GetSiteInstance())
74 ->GetFileSystemContext();
75 storage::FileSystemURL file_system_url(
76 file_system_context->CrackURL(GURL(url)));
78 BrowserThread::PostTask(
81 Bind(&storage::FileSystemContext::DeleteFileSystem,
83 source_url().GetOrigin(),
84 file_system_url.type(),
85 Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem,
90 void SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem(
91 base::File::Error error) {
92 // Repost to switch from IO thread to UI thread for SendResponse().
93 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
94 DCHECK_CURRENTLY_ON(BrowserThread::IO);
95 BrowserThread::PostTask(
98 Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem, this,
103 DCHECK_CURRENTLY_ON(BrowserThread::UI);
104 if (error != base::File::FILE_OK) {
105 error_ = ErrorToString(sync_file_system::FileErrorToSyncStatusCode(error));
106 SetResult(new base::FundamentalValue(false));
111 SetResult(new base::FundamentalValue(true));
115 bool SyncFileSystemRequestFileSystemFunction::RunAsync() {
116 // SyncFileSystem initialization is done in OpenFileSystem below, but we call
117 // GetSyncFileSystemService here too to initialize sync event observer for
119 GetSyncFileSystemService(GetProfile());
121 // Initializes sync context for this extension and continue to open
122 // a new file system.
123 BrowserThread::PostTask(BrowserThread::IO,
125 Bind(&storage::FileSystemContext::OpenFileSystem,
126 GetFileSystemContext(),
127 source_url().GetOrigin(),
128 storage::kFileSystemTypeSyncable,
129 storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
130 base::Bind(&self::DidOpenFileSystem, this)));
134 storage::FileSystemContext*
135 SyncFileSystemRequestFileSystemFunction::GetFileSystemContext() {
136 DCHECK(render_view_host());
137 return BrowserContext::GetStoragePartition(
138 GetProfile(), render_view_host()->GetSiteInstance())
139 ->GetFileSystemContext();
142 void SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem(
143 const GURL& root_url,
144 const std::string& file_system_name,
145 base::File::Error error) {
146 // Repost to switch from IO thread to UI thread for SendResponse().
147 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
148 DCHECK_CURRENTLY_ON(BrowserThread::IO);
149 BrowserThread::PostTask(
150 BrowserThread::UI, FROM_HERE,
151 Bind(&SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem,
152 this, root_url, file_system_name, error));
156 DCHECK_CURRENTLY_ON(BrowserThread::UI);
157 if (error != base::File::FILE_OK) {
158 error_ = ErrorToString(sync_file_system::FileErrorToSyncStatusCode(error));
163 base::DictionaryValue* dict = new base::DictionaryValue();
165 dict->SetString("name", file_system_name);
166 dict->SetString("root", root_url.spec());
170 bool SyncFileSystemGetFileStatusFunction::RunAsync() {
172 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
174 scoped_refptr<storage::FileSystemContext> file_system_context =
175 BrowserContext::GetStoragePartition(GetProfile(),
176 render_view_host()->GetSiteInstance())
177 ->GetFileSystemContext();
178 storage::FileSystemURL file_system_url(
179 file_system_context->CrackURL(GURL(url)));
181 GetSyncFileSystemService(GetProfile())->GetFileSyncStatus(
183 Bind(&SyncFileSystemGetFileStatusFunction::DidGetFileStatus, this));
187 void SyncFileSystemGetFileStatusFunction::DidGetFileStatus(
188 const SyncStatusCode sync_status_code,
189 const SyncFileStatus sync_file_status) {
190 DCHECK_CURRENTLY_ON(BrowserThread::UI);
191 if (sync_status_code != sync_file_system::SYNC_STATUS_OK) {
192 error_ = ErrorToString(sync_status_code);
197 // Convert from C++ to JavaScript enum.
198 results_ = api::sync_file_system::GetFileStatus::Results::Create(
199 SyncFileStatusToExtensionEnum(sync_file_status));
203 SyncFileSystemGetFileStatusesFunction::SyncFileSystemGetFileStatusesFunction() {
206 SyncFileSystemGetFileStatusesFunction::~SyncFileSystemGetFileStatusesFunction(
209 bool SyncFileSystemGetFileStatusesFunction::RunAsync() {
210 // All FileEntries converted into array of URL Strings in JS custom bindings.
211 base::ListValue* file_entry_urls = NULL;
212 EXTENSION_FUNCTION_VALIDATE(args_->GetList(0, &file_entry_urls));
214 scoped_refptr<storage::FileSystemContext> file_system_context =
215 BrowserContext::GetStoragePartition(GetProfile(),
216 render_view_host()->GetSiteInstance())
217 ->GetFileSystemContext();
219 // Map each file path->SyncFileStatus in the callback map.
220 // TODO(calvinlo): Overload GetFileSyncStatus to take in URL array.
221 num_expected_results_ = file_entry_urls->GetSize();
222 num_results_received_ = 0;
223 file_sync_statuses_.clear();
224 sync_file_system::SyncFileSystemService* sync_file_system_service =
225 GetSyncFileSystemService(GetProfile());
226 for (unsigned int i = 0; i < num_expected_results_; i++) {
228 file_entry_urls->GetString(i, &url);
229 storage::FileSystemURL file_system_url(
230 file_system_context->CrackURL(GURL(url)));
232 sync_file_system_service->GetFileSyncStatus(
234 Bind(&SyncFileSystemGetFileStatusesFunction::DidGetFileStatus,
235 this, file_system_url));
241 void SyncFileSystemGetFileStatusesFunction::DidGetFileStatus(
242 const storage::FileSystemURL& file_system_url,
243 SyncStatusCode sync_status_code,
244 SyncFileStatus sync_file_status) {
245 DCHECK_CURRENTLY_ON(BrowserThread::UI);
246 num_results_received_++;
247 DCHECK_LE(num_results_received_, num_expected_results_);
249 file_sync_statuses_[file_system_url] =
250 std::make_pair(sync_status_code, sync_file_status);
252 // Keep mapping file statuses until all of them have been received.
253 // TODO(calvinlo): Get rid of this check when batch version of
254 // GetFileSyncStatus(GURL urls[]); is added.
255 if (num_results_received_ < num_expected_results_)
258 // All results received. Dump array of statuses into extension enum values.
259 // Note that the enum types need to be set as strings manually as the
260 // autogenerated Results::Create function thinks the enum values should be
261 // returned as int values.
262 base::ListValue* status_array = new base::ListValue();
263 for (URLToStatusMap::iterator it = file_sync_statuses_.begin();
264 it != file_sync_statuses_.end(); ++it) {
265 base::DictionaryValue* dict = new base::DictionaryValue();
266 status_array->Append(dict);
268 storage::FileSystemURL url = it->first;
269 SyncStatusCode file_error = it->second.first;
270 api::sync_file_system::FileStatus file_status =
271 SyncFileStatusToExtensionEnum(it->second.second);
273 dict->Set("entry", CreateDictionaryValueForFileSystemEntry(
274 url, sync_file_system::SYNC_FILE_TYPE_FILE));
275 dict->SetString("status", ToString(file_status));
277 if (file_error == sync_file_system::SYNC_STATUS_OK)
279 dict->SetString("error", ErrorToString(file_error));
281 SetResult(status_array);
286 bool SyncFileSystemGetUsageAndQuotaFunction::RunAsync() {
288 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
290 scoped_refptr<storage::FileSystemContext> file_system_context =
291 BrowserContext::GetStoragePartition(GetProfile(),
292 render_view_host()->GetSiteInstance())
293 ->GetFileSystemContext();
294 storage::FileSystemURL file_system_url(
295 file_system_context->CrackURL(GURL(url)));
297 scoped_refptr<storage::QuotaManager> quota_manager =
298 BrowserContext::GetStoragePartition(GetProfile(),
299 render_view_host()->GetSiteInstance())
302 BrowserThread::PostTask(
305 Bind(&storage::QuotaManager::GetUsageAndQuotaForWebApps,
307 source_url().GetOrigin(),
308 storage::FileSystemTypeToQuotaStorageType(file_system_url.type()),
309 Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota,
315 void SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota(
316 storage::QuotaStatusCode status,
319 // Repost to switch from IO thread to UI thread for SendResponse().
320 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
321 DCHECK_CURRENTLY_ON(BrowserThread::IO);
322 BrowserThread::PostTask(
325 Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota, this,
326 status, usage, quota));
330 DCHECK_CURRENTLY_ON(BrowserThread::UI);
331 if (status != storage::kQuotaStatusOk) {
332 error_ = QuotaStatusCodeToString(status);
337 api::sync_file_system::StorageInfo info;
338 info.usage_bytes = usage;
339 info.quota_bytes = quota;
340 results_ = api::sync_file_system::GetUsageAndQuota::Results::Create(info);
344 bool SyncFileSystemSetConflictResolutionPolicyFunction::RunSync() {
345 std::string policy_string;
346 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &policy_string));
347 ConflictResolutionPolicy policy = ExtensionEnumToConflictResolutionPolicy(
348 api::sync_file_system::ParseConflictResolutionPolicy(policy_string));
349 if (policy != sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN) {
350 SetError(base::StringPrintf(kUnsupportedConflictResolutionPolicy,
351 policy_string.c_str()));
357 bool SyncFileSystemGetConflictResolutionPolicyFunction::RunSync() {
358 SetResult(new base::StringValue(
359 api::sync_file_system::ToString(
360 api::sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN)));
364 bool SyncFileSystemGetServiceStatusFunction::RunSync() {
365 sync_file_system::SyncFileSystemService* service =
366 GetSyncFileSystemService(GetProfile());
367 results_ = api::sync_file_system::GetServiceStatus::Results::Create(
368 SyncServiceStateToExtensionEnum(service->GetSyncServiceState()));
372 } // namespace extensions