• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/extensions/api/sync_file_system/sync_file_system_api.h"
6 
7 #include <string>
8 #include <utility>
9 
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"
30 
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;
37 
38 namespace extensions {
39 
40 namespace {
41 
42 // Error messages.
43 const char kErrorMessage[] = "%s (error code: %d).";
44 const char kUnsupportedConflictResolutionPolicy[] =
45     "Policy %s is not supported.";
46 
GetSyncFileSystemService(Profile * profile)47 sync_file_system::SyncFileSystemService* GetSyncFileSystemService(
48     Profile* profile) {
49   sync_file_system::SyncFileSystemService* service =
50       SyncFileSystemServiceFactory::GetForProfile(profile);
51   DCHECK(service);
52   ExtensionSyncEventObserver* observer =
53       ExtensionSyncEventObserver::GetFactoryInstance()->Get(profile);
54   DCHECK(observer);
55   observer->InitializeForService(service);
56   return service;
57 }
58 
ErrorToString(SyncStatusCode code)59 std::string ErrorToString(SyncStatusCode code) {
60   return base::StringPrintf(
61       kErrorMessage,
62       sync_file_system::SyncStatusCodeToString(code),
63       static_cast<int>(code));
64 }
65 
66 }  // namespace
67 
RunAsync()68 bool SyncFileSystemDeleteFileSystemFunction::RunAsync() {
69   std::string url;
70   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
71 
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)));
78 
79   BrowserThread::PostTask(
80       BrowserThread::IO,
81       FROM_HERE,
82       Bind(&fileapi::FileSystemContext::DeleteFileSystem,
83            file_system_context,
84            source_url().GetOrigin(),
85            file_system_url.type(),
86            Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem,
87                 this)));
88   return true;
89 }
90 
DidDeleteFileSystem(base::File::Error error)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(
97         BrowserThread::UI,
98         FROM_HERE,
99         Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem, this,
100              error));
101     return;
102   }
103 
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));
108     SendResponse(false);
109     return;
110   }
111 
112   SetResult(new base::FundamentalValue(true));
113   SendResponse(true);
114 }
115 
RunAsync()116 bool SyncFileSystemRequestFileSystemFunction::RunAsync() {
117   // SyncFileSystem initialization is done in OpenFileSystem below, but we call
118   // GetSyncFileSystemService here too to initialize sync event observer for
119   // extensions API.
120   GetSyncFileSystemService(GetProfile());
121 
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)));
132   return true;
133 }
134 
135 fileapi::FileSystemContext*
GetFileSystemContext()136 SyncFileSystemRequestFileSystemFunction::GetFileSystemContext() {
137   DCHECK(render_view_host());
138   return BrowserContext::GetStoragePartition(
139       GetProfile(), render_view_host()->GetSiteInstance())
140       ->GetFileSystemContext();
141 }
142 
DidOpenFileSystem(const GURL & root_url,const std::string & file_system_name,base::File::Error error)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));
154     return;
155   }
156 
157   DCHECK_CURRENTLY_ON(BrowserThread::UI);
158   if (error != base::File::FILE_OK) {
159     error_ = ErrorToString(sync_file_system::FileErrorToSyncStatusCode(error));
160     SendResponse(false);
161     return;
162   }
163 
164   base::DictionaryValue* dict = new base::DictionaryValue();
165   SetResult(dict);
166   dict->SetString("name", file_system_name);
167   dict->SetString("root", root_url.spec());
168   SendResponse(true);
169 }
170 
RunAsync()171 bool SyncFileSystemGetFileStatusFunction::RunAsync() {
172   std::string url;
173   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
174 
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)));
181 
182   GetSyncFileSystemService(GetProfile())->GetFileSyncStatus(
183       file_system_url,
184       Bind(&SyncFileSystemGetFileStatusFunction::DidGetFileStatus, this));
185   return true;
186 }
187 
DidGetFileStatus(const SyncStatusCode sync_status_code,const SyncFileStatus sync_file_status)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);
194     SendResponse(false);
195     return;
196   }
197 
198   // Convert from C++ to JavaScript enum.
199   results_ = api::sync_file_system::GetFileStatus::Results::Create(
200       SyncFileStatusToExtensionEnum(sync_file_status));
201   SendResponse(true);
202 }
203 
SyncFileSystemGetFileStatusesFunction()204 SyncFileSystemGetFileStatusesFunction::SyncFileSystemGetFileStatusesFunction() {
205 }
206 
~SyncFileSystemGetFileStatusesFunction()207 SyncFileSystemGetFileStatusesFunction::~SyncFileSystemGetFileStatusesFunction(
208     ) {}
209 
RunAsync()210 bool SyncFileSystemGetFileStatusesFunction::RunAsync() {
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));
214 
215   scoped_refptr<fileapi::FileSystemContext> file_system_context =
216       BrowserContext::GetStoragePartition(GetProfile(),
217                                           render_view_host()->GetSiteInstance())
218           ->GetFileSystemContext();
219 
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++) {
228     std::string url;
229     file_entry_urls->GetString(i, &url);
230     fileapi::FileSystemURL file_system_url(
231         file_system_context->CrackURL(GURL(url)));
232 
233     sync_file_system_service->GetFileSyncStatus(
234         file_system_url,
235         Bind(&SyncFileSystemGetFileStatusesFunction::DidGetFileStatus,
236              this, file_system_url));
237   }
238 
239   return true;
240 }
241 
DidGetFileStatus(const fileapi::FileSystemURL & file_system_url,SyncStatusCode sync_status_code,SyncFileStatus sync_file_status)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_);
249 
250   file_sync_statuses_[file_system_url] =
251       std::make_pair(sync_status_code, sync_file_status);
252 
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_)
257     return;
258 
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);
268 
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);
273 
274     dict->Set("entry", CreateDictionaryValueForFileSystemEntry(
275         url, sync_file_system::SYNC_FILE_TYPE_FILE));
276     dict->SetString("status", ToString(file_status));
277 
278     if (file_error == sync_file_system::SYNC_STATUS_OK)
279       continue;
280     dict->SetString("error", ErrorToString(file_error));
281   }
282   SetResult(status_array);
283 
284   SendResponse(true);
285 }
286 
RunAsync()287 bool SyncFileSystemGetUsageAndQuotaFunction::RunAsync() {
288   std::string url;
289   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
290 
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)));
297 
298   scoped_refptr<quota::QuotaManager> quota_manager =
299       BrowserContext::GetStoragePartition(GetProfile(),
300                                           render_view_host()->GetSiteInstance())
301           ->GetQuotaManager();
302 
303   BrowserThread::PostTask(
304       BrowserThread::IO,
305       FROM_HERE,
306       Bind(&quota::QuotaManager::GetUsageAndQuotaForWebApps,
307            quota_manager,
308            source_url().GetOrigin(),
309            fileapi::FileSystemTypeToQuotaStorageType(file_system_url.type()),
310            Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota,
311                 this)));
312 
313   return true;
314 }
315 
DidGetUsageAndQuota(quota::QuotaStatusCode status,int64 usage,int64 quota)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(
322         BrowserThread::UI,
323         FROM_HERE,
324         Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota, this,
325              status, usage, quota));
326     return;
327   }
328 
329   DCHECK_CURRENTLY_ON(BrowserThread::UI);
330   if (status != quota::kQuotaStatusOk) {
331     error_ = QuotaStatusCodeToString(status);
332     SendResponse(false);
333     return;
334   }
335 
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);
340   SendResponse(true);
341 }
342 
RunSync()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_LAST_WRITE_WIN) {
349     SetError(base::StringPrintf(kUnsupportedConflictResolutionPolicy,
350                                 policy_string.c_str()));
351     return false;
352   }
353   return true;
354 }
355 
RunSync()356 bool SyncFileSystemGetConflictResolutionPolicyFunction::RunSync() {
357   SetResult(new base::StringValue(
358       api::sync_file_system::ToString(
359           api::sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN)));
360   return true;
361 }
362 
RunSync()363 bool SyncFileSystemGetServiceStatusFunction::RunSync() {
364   sync_file_system::SyncFileSystemService* service =
365       GetSyncFileSystemService(GetProfile());
366   results_ = api::sync_file_system::GetServiceStatus::Results::Create(
367       SyncServiceStateToExtensionEnum(service->GetSyncServiceState()));
368   return true;
369 }
370 
371 }  // namespace extensions
372