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_frame_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
);
52 ExtensionSyncEventObserver
* observer
=
53 ExtensionSyncEventObserver::GetFactoryInstance()->Get(profile
);
56 observer
->InitializeForService(service
);
60 std::string
ErrorToString(SyncStatusCode code
) {
61 return base::StringPrintf(
63 sync_file_system::SyncStatusCodeToString(code
),
64 static_cast<int>(code
));
69 bool SyncFileSystemDeleteFileSystemFunction::RunAsync() {
71 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &url
));
73 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
74 BrowserContext::GetStoragePartition(
75 GetProfile(), render_frame_host()->GetSiteInstance())
76 ->GetFileSystemContext();
77 storage::FileSystemURL
file_system_url(
78 file_system_context
->CrackURL(GURL(url
)));
80 BrowserThread::PostTask(
83 Bind(&storage::FileSystemContext::DeleteFileSystem
,
85 source_url().GetOrigin(),
86 file_system_url
.type(),
87 Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem
,
92 void SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem(
93 base::File::Error error
) {
94 // Repost to switch from IO thread to UI thread for SendResponse().
95 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
96 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
97 BrowserThread::PostTask(
100 Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem
, this,
105 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
106 if (error
!= base::File::FILE_OK
) {
107 error_
= ErrorToString(sync_file_system::FileErrorToSyncStatusCode(error
));
108 SetResult(new base::FundamentalValue(false));
113 SetResult(new base::FundamentalValue(true));
117 bool SyncFileSystemRequestFileSystemFunction::RunAsync() {
118 // SyncFileSystem initialization is done in OpenFileSystem below, but we call
119 // GetSyncFileSystemService here too to initialize sync event observer for
121 if (!GetSyncFileSystemService(GetProfile()))
124 // Initializes sync context for this extension and continue to open
125 // a new file system.
126 BrowserThread::PostTask(BrowserThread::IO
,
128 Bind(&storage::FileSystemContext::OpenFileSystem
,
129 GetFileSystemContext(),
130 source_url().GetOrigin(),
131 storage::kFileSystemTypeSyncable
,
132 storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT
,
133 base::Bind(&self::DidOpenFileSystem
, this)));
137 storage::FileSystemContext
*
138 SyncFileSystemRequestFileSystemFunction::GetFileSystemContext() {
139 DCHECK(render_frame_host());
140 return BrowserContext::GetStoragePartition(
141 GetProfile(), render_frame_host()->GetSiteInstance())
142 ->GetFileSystemContext();
145 void SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem(
146 const GURL
& root_url
,
147 const std::string
& file_system_name
,
148 base::File::Error error
) {
149 // Repost to switch from IO thread to UI thread for SendResponse().
150 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
151 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
152 BrowserThread::PostTask(
153 BrowserThread::UI
, FROM_HERE
,
154 Bind(&SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem
,
155 this, root_url
, file_system_name
, error
));
159 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
160 if (error
!= base::File::FILE_OK
) {
161 error_
= ErrorToString(sync_file_system::FileErrorToSyncStatusCode(error
));
166 base::DictionaryValue
* dict
= new base::DictionaryValue();
168 dict
->SetString("name", file_system_name
);
169 dict
->SetString("root", root_url
.spec());
173 bool SyncFileSystemGetFileStatusFunction::RunAsync() {
175 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &url
));
177 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
178 BrowserContext::GetStoragePartition(
179 GetProfile(), render_frame_host()->GetSiteInstance())
180 ->GetFileSystemContext();
181 storage::FileSystemURL
file_system_url(
182 file_system_context
->CrackURL(GURL(url
)));
184 sync_file_system::SyncFileSystemService
* sync_file_system_service
=
185 GetSyncFileSystemService(GetProfile());
186 if (!sync_file_system_service
)
189 sync_file_system_service
->GetFileSyncStatus(
191 Bind(&SyncFileSystemGetFileStatusFunction::DidGetFileStatus
, this));
195 void SyncFileSystemGetFileStatusFunction::DidGetFileStatus(
196 const SyncStatusCode sync_status_code
,
197 const SyncFileStatus sync_file_status
) {
198 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
199 if (sync_status_code
!= sync_file_system::SYNC_STATUS_OK
) {
200 error_
= ErrorToString(sync_status_code
);
205 // Convert from C++ to JavaScript enum.
206 results_
= api::sync_file_system::GetFileStatus::Results::Create(
207 SyncFileStatusToExtensionEnum(sync_file_status
));
211 SyncFileSystemGetFileStatusesFunction::SyncFileSystemGetFileStatusesFunction() {
214 SyncFileSystemGetFileStatusesFunction::~SyncFileSystemGetFileStatusesFunction(
217 bool SyncFileSystemGetFileStatusesFunction::RunAsync() {
218 // All FileEntries converted into array of URL Strings in JS custom bindings.
219 base::ListValue
* file_entry_urls
= NULL
;
220 EXTENSION_FUNCTION_VALIDATE(args_
->GetList(0, &file_entry_urls
));
222 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
223 BrowserContext::GetStoragePartition(
224 GetProfile(), render_frame_host()->GetSiteInstance())
225 ->GetFileSystemContext();
227 // Map each file path->SyncFileStatus in the callback map.
228 // TODO(calvinlo): Overload GetFileSyncStatus to take in URL array.
229 num_expected_results_
= file_entry_urls
->GetSize();
230 num_results_received_
= 0;
231 file_sync_statuses_
.clear();
232 sync_file_system::SyncFileSystemService
* sync_file_system_service
=
233 GetSyncFileSystemService(GetProfile());
234 if (!sync_file_system_service
)
237 for (unsigned int i
= 0; i
< num_expected_results_
; i
++) {
239 file_entry_urls
->GetString(i
, &url
);
240 storage::FileSystemURL
file_system_url(
241 file_system_context
->CrackURL(GURL(url
)));
243 sync_file_system_service
->GetFileSyncStatus(
245 Bind(&SyncFileSystemGetFileStatusesFunction::DidGetFileStatus
,
246 this, file_system_url
));
252 void SyncFileSystemGetFileStatusesFunction::DidGetFileStatus(
253 const storage::FileSystemURL
& file_system_url
,
254 SyncStatusCode sync_status_code
,
255 SyncFileStatus sync_file_status
) {
256 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
257 num_results_received_
++;
258 DCHECK_LE(num_results_received_
, num_expected_results_
);
260 file_sync_statuses_
[file_system_url
] =
261 std::make_pair(sync_status_code
, sync_file_status
);
263 // Keep mapping file statuses until all of them have been received.
264 // TODO(calvinlo): Get rid of this check when batch version of
265 // GetFileSyncStatus(GURL urls[]); is added.
266 if (num_results_received_
< num_expected_results_
)
269 // All results received. Dump array of statuses into extension enum values.
270 // Note that the enum types need to be set as strings manually as the
271 // autogenerated Results::Create function thinks the enum values should be
272 // returned as int values.
273 base::ListValue
* status_array
= new base::ListValue();
274 for (URLToStatusMap::iterator it
= file_sync_statuses_
.begin();
275 it
!= file_sync_statuses_
.end(); ++it
) {
276 base::DictionaryValue
* dict
= new base::DictionaryValue();
277 status_array
->Append(dict
);
279 storage::FileSystemURL url
= it
->first
;
280 SyncStatusCode file_error
= it
->second
.first
;
281 api::sync_file_system::FileStatus file_status
=
282 SyncFileStatusToExtensionEnum(it
->second
.second
);
284 dict
->Set("entry", CreateDictionaryValueForFileSystemEntry(
285 url
, sync_file_system::SYNC_FILE_TYPE_FILE
));
286 dict
->SetString("status", ToString(file_status
));
288 if (file_error
== sync_file_system::SYNC_STATUS_OK
)
290 dict
->SetString("error", ErrorToString(file_error
));
292 SetResult(status_array
);
297 bool SyncFileSystemGetUsageAndQuotaFunction::RunAsync() {
299 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &url
));
301 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
302 BrowserContext::GetStoragePartition(
303 GetProfile(), render_frame_host()->GetSiteInstance())
304 ->GetFileSystemContext();
305 storage::FileSystemURL
file_system_url(
306 file_system_context
->CrackURL(GURL(url
)));
308 scoped_refptr
<storage::QuotaManager
> quota_manager
=
309 BrowserContext::GetStoragePartition(
310 GetProfile(), render_frame_host()->GetSiteInstance())
313 BrowserThread::PostTask(
316 Bind(&storage::QuotaManager::GetUsageAndQuotaForWebApps
,
318 source_url().GetOrigin(),
319 storage::FileSystemTypeToQuotaStorageType(file_system_url
.type()),
320 Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota
,
326 void SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota(
327 storage::QuotaStatusCode status
,
330 // Repost to switch from IO thread to UI thread for SendResponse().
331 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
332 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
333 BrowserThread::PostTask(
336 Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota
, this,
337 status
, usage
, quota
));
341 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
342 if (status
!= storage::kQuotaStatusOk
) {
343 error_
= QuotaStatusCodeToString(status
);
348 api::sync_file_system::StorageInfo info
;
349 info
.usage_bytes
= usage
;
350 info
.quota_bytes
= quota
;
351 results_
= api::sync_file_system::GetUsageAndQuota::Results::Create(info
);
355 bool SyncFileSystemSetConflictResolutionPolicyFunction::RunSync() {
356 std::string policy_string
;
357 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &policy_string
));
358 ConflictResolutionPolicy policy
= ExtensionEnumToConflictResolutionPolicy(
359 api::sync_file_system::ParseConflictResolutionPolicy(policy_string
));
360 if (policy
!= sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN
) {
361 SetError(base::StringPrintf(kUnsupportedConflictResolutionPolicy
,
362 policy_string
.c_str()));
368 bool SyncFileSystemGetConflictResolutionPolicyFunction::RunSync() {
369 SetResult(new base::StringValue(
370 api::sync_file_system::ToString(
371 api::sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN
)));
375 bool SyncFileSystemGetServiceStatusFunction::RunSync() {
376 sync_file_system::SyncFileSystemService
* service
=
377 GetSyncFileSystemService(GetProfile());
380 results_
= api::sync_file_system::GetServiceStatus::Results::Create(
381 SyncServiceStateToExtensionEnum(service
->GetSyncServiceState()));
385 } // namespace extensions