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/drive_backend_v1/drive_file_sync_service.h"
17 #include "chrome/browser/sync_file_system/sync_file_status.h"
18 #include "chrome/browser/sync_file_system/sync_file_system_service.h"
19 #include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
20 #include "chrome/common/extensions/api/sync_file_system.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "content/public/browser/storage_partition.h"
24 #include "content/public/common/content_client.h"
25 #include "webkit/browser/fileapi/file_system_context.h"
26 #include "webkit/browser/fileapi/file_system_url.h"
27 #include "webkit/browser/quota/quota_manager.h"
28 #include "webkit/common/fileapi/file_system_types.h"
29 #include "webkit/common/fileapi/file_system_util.h"
31 using content::BrowserContext
;
32 using content::BrowserThread
;
33 using sync_file_system::ConflictResolutionPolicy
;
34 using sync_file_system::SyncFileStatus
;
35 using sync_file_system::SyncFileSystemServiceFactory
;
36 using sync_file_system::SyncStatusCode
;
38 namespace extensions
{
43 const char kErrorMessage
[] = "%s (error code: %d).";
44 const char kUnsupportedConflictResolutionPolicy
[] =
45 "Policy %s is not supported.";
47 sync_file_system::SyncFileSystemService
* GetSyncFileSystemService(
49 sync_file_system::SyncFileSystemService
* service
=
50 SyncFileSystemServiceFactory::GetForProfile(profile
);
52 ExtensionSyncEventObserver
* observer
=
53 ExtensionSyncEventObserver::GetFactoryInstance()->Get(profile
);
55 observer
->InitializeForService(service
);
59 std::string
ErrorToString(SyncStatusCode code
) {
60 return base::StringPrintf(
62 sync_file_system::SyncStatusCodeToString(code
),
63 static_cast<int>(code
));
68 bool SyncFileSystemDeleteFileSystemFunction::RunImpl() {
70 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &url
));
72 scoped_refptr
<fileapi::FileSystemContext
> file_system_context
=
73 BrowserContext::GetStoragePartition(GetProfile(),
74 render_view_host()->GetSiteInstance())
75 ->GetFileSystemContext();
76 fileapi::FileSystemURL
file_system_url(
77 file_system_context
->CrackURL(GURL(url
)));
79 BrowserThread::PostTask(
82 Bind(&fileapi::FileSystemContext::DeleteFileSystem
,
84 source_url().GetOrigin(),
85 file_system_url
.type(),
86 Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem
,
91 void SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem(
92 base::File::Error error
) {
93 // Repost to switch from IO thread to UI thread for SendResponse().
94 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
95 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
96 BrowserThread::PostTask(
99 Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem
, this,
104 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
105 if (error
!= base::File::FILE_OK
) {
106 error_
= ErrorToString(sync_file_system::FileErrorToSyncStatusCode(error
));
107 SetResult(new base::FundamentalValue(false));
112 SetResult(new base::FundamentalValue(true));
116 bool SyncFileSystemRequestFileSystemFunction::RunImpl() {
117 // SyncFileSystem initialization is done in OpenFileSystem below, but we call
118 // GetSyncFileSystemService here too to initialize sync event observer for
120 GetSyncFileSystemService(GetProfile());
122 // Initializes sync context for this extension and continue to open
123 // a new file system.
124 BrowserThread::PostTask(
125 BrowserThread::IO
, FROM_HERE
,
126 Bind(&fileapi::FileSystemContext::OpenFileSystem
,
127 GetFileSystemContext(),
128 source_url().GetOrigin(),
129 fileapi::kFileSystemTypeSyncable
,
130 fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT
,
131 base::Bind(&self::DidOpenFileSystem
, this)));
135 fileapi::FileSystemContext
*
136 SyncFileSystemRequestFileSystemFunction::GetFileSystemContext() {
137 DCHECK(render_view_host());
138 return BrowserContext::GetStoragePartition(
139 GetProfile(), render_view_host()->GetSiteInstance())
140 ->GetFileSystemContext();
143 void SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem(
144 const GURL
& root_url
,
145 const std::string
& file_system_name
,
146 base::File::Error error
) {
147 // Repost to switch from IO thread to UI thread for SendResponse().
148 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
149 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
150 BrowserThread::PostTask(
151 BrowserThread::UI
, FROM_HERE
,
152 Bind(&SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem
,
153 this, root_url
, file_system_name
, error
));
157 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
158 if (error
!= base::File::FILE_OK
) {
159 error_
= ErrorToString(sync_file_system::FileErrorToSyncStatusCode(error
));
164 base::DictionaryValue
* dict
= new base::DictionaryValue();
166 dict
->SetString("name", file_system_name
);
167 dict
->SetString("root", root_url
.spec());
171 bool SyncFileSystemGetFileStatusFunction::RunImpl() {
173 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &url
));
175 scoped_refptr
<fileapi::FileSystemContext
> file_system_context
=
176 BrowserContext::GetStoragePartition(GetProfile(),
177 render_view_host()->GetSiteInstance())
178 ->GetFileSystemContext();
179 fileapi::FileSystemURL
file_system_url(
180 file_system_context
->CrackURL(GURL(url
)));
182 GetSyncFileSystemService(GetProfile())->GetFileSyncStatus(
184 Bind(&SyncFileSystemGetFileStatusFunction::DidGetFileStatus
, this));
188 void SyncFileSystemGetFileStatusFunction::DidGetFileStatus(
189 const SyncStatusCode sync_status_code
,
190 const SyncFileStatus sync_file_status
) {
191 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
192 if (sync_status_code
!= sync_file_system::SYNC_STATUS_OK
) {
193 error_
= ErrorToString(sync_status_code
);
198 // Convert from C++ to JavaScript enum.
199 results_
= api::sync_file_system::GetFileStatus::Results::Create(
200 SyncFileStatusToExtensionEnum(sync_file_status
));
204 SyncFileSystemGetFileStatusesFunction::SyncFileSystemGetFileStatusesFunction() {
207 SyncFileSystemGetFileStatusesFunction::~SyncFileSystemGetFileStatusesFunction(
210 bool SyncFileSystemGetFileStatusesFunction::RunImpl() {
211 // All FileEntries converted into array of URL Strings in JS custom bindings.
212 base::ListValue
* file_entry_urls
= NULL
;
213 EXTENSION_FUNCTION_VALIDATE(args_
->GetList(0, &file_entry_urls
));
215 scoped_refptr
<fileapi::FileSystemContext
> file_system_context
=
216 BrowserContext::GetStoragePartition(GetProfile(),
217 render_view_host()->GetSiteInstance())
218 ->GetFileSystemContext();
220 // Map each file path->SyncFileStatus in the callback map.
221 // TODO(calvinlo): Overload GetFileSyncStatus to take in URL array.
222 num_expected_results_
= file_entry_urls
->GetSize();
223 num_results_received_
= 0;
224 file_sync_statuses_
.clear();
225 sync_file_system::SyncFileSystemService
* sync_file_system_service
=
226 GetSyncFileSystemService(GetProfile());
227 for (unsigned int i
= 0; i
< num_expected_results_
; i
++) {
229 file_entry_urls
->GetString(i
, &url
);
230 fileapi::FileSystemURL
file_system_url(
231 file_system_context
->CrackURL(GURL(url
)));
233 sync_file_system_service
->GetFileSyncStatus(
235 Bind(&SyncFileSystemGetFileStatusesFunction::DidGetFileStatus
,
236 this, file_system_url
));
242 void SyncFileSystemGetFileStatusesFunction::DidGetFileStatus(
243 const fileapi::FileSystemURL
& file_system_url
,
244 SyncStatusCode sync_status_code
,
245 SyncFileStatus sync_file_status
) {
246 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
247 num_results_received_
++;
248 DCHECK_LE(num_results_received_
, num_expected_results_
);
250 file_sync_statuses_
[file_system_url
] =
251 std::make_pair(sync_status_code
, sync_file_status
);
253 // Keep mapping file statuses until all of them have been received.
254 // TODO(calvinlo): Get rid of this check when batch version of
255 // GetFileSyncStatus(GURL urls[]); is added.
256 if (num_results_received_
< num_expected_results_
)
259 // All results received. Dump array of statuses into extension enum values.
260 // Note that the enum types need to be set as strings manually as the
261 // autogenerated Results::Create function thinks the enum values should be
262 // returned as int values.
263 base::ListValue
* status_array
= new base::ListValue();
264 for (URLToStatusMap::iterator it
= file_sync_statuses_
.begin();
265 it
!= file_sync_statuses_
.end(); ++it
) {
266 base::DictionaryValue
* dict
= new base::DictionaryValue();
267 status_array
->Append(dict
);
269 fileapi::FileSystemURL url
= it
->first
;
270 SyncStatusCode file_error
= it
->second
.first
;
271 api::sync_file_system::FileStatus file_status
=
272 SyncFileStatusToExtensionEnum(it
->second
.second
);
274 dict
->Set("entry", CreateDictionaryValueForFileSystemEntry(
275 url
, sync_file_system::SYNC_FILE_TYPE_FILE
));
276 dict
->SetString("status", ToString(file_status
));
278 if (file_error
== sync_file_system::SYNC_STATUS_OK
)
280 dict
->SetString("error", ErrorToString(file_error
));
282 SetResult(status_array
);
287 bool SyncFileSystemGetUsageAndQuotaFunction::RunImpl() {
289 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &url
));
291 scoped_refptr
<fileapi::FileSystemContext
> file_system_context
=
292 BrowserContext::GetStoragePartition(GetProfile(),
293 render_view_host()->GetSiteInstance())
294 ->GetFileSystemContext();
295 fileapi::FileSystemURL
file_system_url(
296 file_system_context
->CrackURL(GURL(url
)));
298 scoped_refptr
<quota::QuotaManager
> quota_manager
=
299 BrowserContext::GetStoragePartition(GetProfile(),
300 render_view_host()->GetSiteInstance())
303 BrowserThread::PostTask(
306 Bind("a::QuotaManager::GetUsageAndQuotaForWebApps
,
308 source_url().GetOrigin(),
309 fileapi::FileSystemTypeToQuotaStorageType(file_system_url
.type()),
310 Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota
,
316 void SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota(
317 quota::QuotaStatusCode status
, int64 usage
, int64 quota
) {
318 // Repost to switch from IO thread to UI thread for SendResponse().
319 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
320 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
321 BrowserThread::PostTask(
324 Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota
, this,
325 status
, usage
, quota
));
329 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
330 if (status
!= quota::kQuotaStatusOk
) {
331 error_
= QuotaStatusCodeToString(status
);
336 api::sync_file_system::StorageInfo info
;
337 info
.usage_bytes
= usage
;
338 info
.quota_bytes
= quota
;
339 results_
= api::sync_file_system::GetUsageAndQuota::Results::Create(info
);
343 bool SyncFileSystemSetConflictResolutionPolicyFunction::RunSync() {
344 std::string policy_string
;
345 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &policy_string
));
346 ConflictResolutionPolicy policy
= ExtensionEnumToConflictResolutionPolicy(
347 api::sync_file_system::ParseConflictResolutionPolicy(policy_string
));
348 if (policy
== sync_file_system::CONFLICT_RESOLUTION_POLICY_UNKNOWN
) {
349 SetError(base::StringPrintf(kUnsupportedConflictResolutionPolicy
,
350 policy_string
.c_str()));
353 sync_file_system::SyncFileSystemService
* service
=
354 GetSyncFileSystemService(GetProfile());
356 SyncStatusCode status
= service
->SetConflictResolutionPolicy(
357 source_url().GetOrigin(), policy
);
358 if (status
!= sync_file_system::SYNC_STATUS_OK
) {
359 SetError(ErrorToString(status
));
365 bool SyncFileSystemGetConflictResolutionPolicyFunction::RunSync() {
366 sync_file_system::SyncFileSystemService
* service
=
367 GetSyncFileSystemService(GetProfile());
369 api::sync_file_system::ConflictResolutionPolicy policy
=
370 ConflictResolutionPolicyToExtensionEnum(
371 service
->GetConflictResolutionPolicy(source_url().GetOrigin()));
372 SetResult(new base::StringValue(
373 api::sync_file_system::ToString(policy
)));
377 bool SyncFileSystemGetServiceStatusFunction::RunSync() {
378 sync_file_system::SyncFileSystemService
* service
=
379 GetSyncFileSystemService(GetProfile());
380 results_
= api::sync_file_system::GetServiceStatus::Results::Create(
381 SyncServiceStateToExtensionEnum(service
->GetSyncServiceState()));
385 } // namespace extensions