Home | History | Annotate | Download | only in sync_file_system
      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/extension_sync_event_observer_factory.h"
     15 #include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.h"
     18 #include "chrome/browser/sync_file_system/sync_file_status.h"
     19 #include "chrome/browser/sync_file_system/sync_file_system_service.h"
     20 #include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
     21 #include "chrome/common/extensions/api/sync_file_system.h"
     22 #include "content/public/browser/browser_context.h"
     23 #include "content/public/browser/render_view_host.h"
     24 #include "content/public/browser/storage_partition.h"
     25 #include "content/public/common/content_client.h"
     26 #include "webkit/browser/fileapi/file_system_context.h"
     27 #include "webkit/browser/fileapi/file_system_url.h"
     28 #include "webkit/browser/quota/quota_manager.h"
     29 #include "webkit/common/fileapi/file_system_types.h"
     30 #include "webkit/common/fileapi/file_system_util.h"
     31 
     32 using content::BrowserContext;
     33 using content::BrowserThread;
     34 using sync_file_system::ConflictResolutionPolicy;
     35 using sync_file_system::SyncFileStatus;
     36 using sync_file_system::SyncFileSystemServiceFactory;
     37 using sync_file_system::SyncStatusCode;
     38 
     39 namespace extensions {
     40 
     41 namespace {
     42 
     43 // Error messages.
     44 const char kFileError[] = "File error %d.";
     45 const char kQuotaError[] = "Quota error %d.";
     46 const char kUnsupportedConflictResolutionPolicy[] =
     47     "Policy %s is not supported.";
     48 
     49 sync_file_system::SyncFileSystemService* GetSyncFileSystemService(
     50     Profile* profile) {
     51   sync_file_system::SyncFileSystemService* service =
     52       SyncFileSystemServiceFactory::GetForProfile(profile);
     53   DCHECK(service);
     54   ExtensionSyncEventObserver* observer =
     55       ExtensionSyncEventObserverFactory::GetForProfile(profile);
     56   DCHECK(observer);
     57   observer->InitializeForService(service);
     58   return service;
     59 }
     60 
     61 }  // namespace
     62 
     63 bool SyncFileSystemDeleteFileSystemFunction::RunImpl() {
     64   std::string url;
     65   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
     66 
     67   scoped_refptr<fileapi::FileSystemContext> file_system_context =
     68       BrowserContext::GetStoragePartition(
     69           profile(),
     70           render_view_host()->GetSiteInstance())->GetFileSystemContext();
     71   fileapi::FileSystemURL file_system_url(
     72       file_system_context->CrackURL(GURL(url)));
     73 
     74   BrowserThread::PostTask(
     75       BrowserThread::IO,
     76       FROM_HERE,
     77       Bind(&fileapi::FileSystemContext::DeleteFileSystem,
     78            file_system_context,
     79            source_url().GetOrigin(),
     80            file_system_url.type(),
     81            Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem,
     82                 this)));
     83   return true;
     84 }
     85 
     86 void SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem(
     87     base::PlatformFileError error) {
     88   // Repost to switch from IO thread to UI thread for SendResponse().
     89   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     90     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     91     BrowserThread::PostTask(
     92         BrowserThread::UI,
     93         FROM_HERE,
     94         Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem, this,
     95              error));
     96     return;
     97   }
     98 
     99   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    100   if (error != base::PLATFORM_FILE_OK) {
    101     error_ = base::StringPrintf(kFileError, static_cast<int>(error));
    102     SetResult(base::Value::CreateBooleanValue(false));
    103     SendResponse(false);
    104     return;
    105   }
    106 
    107   SetResult(base::Value::CreateBooleanValue(true));
    108   SendResponse(true);
    109 }
    110 
    111 bool SyncFileSystemRequestFileSystemFunction::RunImpl() {
    112   // Initializes sync context for this extension and continue to open
    113   // a new file system.
    114   GetSyncFileSystemService(profile())->
    115       InitializeForApp(
    116           GetFileSystemContext(),
    117           source_url().GetOrigin(),
    118           base::Bind(&self::DidInitializeFileSystemContext, this));
    119   return true;
    120 }
    121 
    122 fileapi::FileSystemContext*
    123 SyncFileSystemRequestFileSystemFunction::GetFileSystemContext() {
    124   DCHECK(render_view_host());
    125   return BrowserContext::GetStoragePartition(
    126       profile(),
    127       render_view_host()->GetSiteInstance())->GetFileSystemContext();
    128 }
    129 
    130 void SyncFileSystemRequestFileSystemFunction::DidInitializeFileSystemContext(
    131     SyncStatusCode status) {
    132   if (status != sync_file_system::SYNC_STATUS_OK) {
    133     error_ = sync_file_system::SyncStatusCodeToString(status);
    134     SendResponse(false);
    135     return;
    136   }
    137 
    138   if (!render_view_host()) {
    139     // The app seems to have been closed.
    140     return;
    141   }
    142 
    143   BrowserThread::PostTask(
    144       BrowserThread::IO, FROM_HERE,
    145       Bind(&fileapi::FileSystemContext::OpenFileSystem,
    146            GetFileSystemContext(),
    147            source_url().GetOrigin(),
    148            fileapi::kFileSystemTypeSyncable,
    149            fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
    150            base::Bind(&self::DidOpenFileSystem, this)));
    151 }
    152 
    153 void SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem(
    154     base::PlatformFileError error,
    155     const std::string& file_system_name,
    156     const GURL& root_url) {
    157   // Repost to switch from IO thread to UI thread for SendResponse().
    158   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    159     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    160     BrowserThread::PostTask(
    161         BrowserThread::UI, FROM_HERE,
    162         Bind(&SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem,
    163              this, error, file_system_name, root_url));
    164     return;
    165   }
    166 
    167   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    168   if (error != base::PLATFORM_FILE_OK) {
    169     error_ = base::StringPrintf(kFileError, static_cast<int>(error));
    170     SendResponse(false);
    171     return;
    172   }
    173 
    174   base::DictionaryValue* dict = new base::DictionaryValue();
    175   SetResult(dict);
    176   dict->SetString("name", file_system_name);
    177   dict->SetString("root", root_url.spec());
    178   SendResponse(true);
    179 }
    180 
    181 bool SyncFileSystemGetFileStatusFunction::RunImpl() {
    182   std::string url;
    183   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
    184 
    185   scoped_refptr<fileapi::FileSystemContext> file_system_context =
    186       BrowserContext::GetStoragePartition(
    187           profile(),
    188           render_view_host()->GetSiteInstance())->GetFileSystemContext();
    189   fileapi::FileSystemURL file_system_url(
    190       file_system_context->CrackURL(GURL(url)));
    191 
    192   SyncFileSystemServiceFactory::GetForProfile(profile())->GetFileSyncStatus(
    193       file_system_url,
    194       Bind(&SyncFileSystemGetFileStatusFunction::DidGetFileStatus,
    195            this));
    196   return true;
    197 }
    198 
    199 void SyncFileSystemGetFileStatusFunction::DidGetFileStatus(
    200     const SyncStatusCode sync_status_code,
    201     const SyncFileStatus sync_file_status) {
    202   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    203   if (sync_status_code != sync_file_system::SYNC_STATUS_OK) {
    204     error_ = sync_file_system::SyncStatusCodeToString(sync_status_code);
    205     SendResponse(false);
    206     return;
    207   }
    208 
    209   // Convert from C++ to JavaScript enum.
    210   results_ = api::sync_file_system::GetFileStatus::Results::Create(
    211       SyncFileStatusToExtensionEnum(sync_file_status));
    212   SendResponse(true);
    213 }
    214 
    215 SyncFileSystemGetFileStatusesFunction::SyncFileSystemGetFileStatusesFunction() {
    216 }
    217 
    218 SyncFileSystemGetFileStatusesFunction::~SyncFileSystemGetFileStatusesFunction(
    219     ) {}
    220 
    221 bool SyncFileSystemGetFileStatusesFunction::RunImpl() {
    222   // All FileEntries converted into array of URL Strings in JS custom bindings.
    223   base::ListValue* file_entry_urls = NULL;
    224   EXTENSION_FUNCTION_VALIDATE(args_->GetList(0, &file_entry_urls));
    225 
    226   scoped_refptr<fileapi::FileSystemContext> file_system_context =
    227       BrowserContext::GetStoragePartition(
    228           profile(),
    229           render_view_host()->GetSiteInstance())->GetFileSystemContext();
    230 
    231   // Map each file path->SyncFileStatus in the callback map.
    232   // TODO(calvinlo): Overload GetFileSyncStatus to take in URL array.
    233   num_expected_results_ = file_entry_urls->GetSize();
    234   num_results_received_ = 0;
    235   file_sync_statuses_.clear();
    236   sync_file_system::SyncFileSystemService* sync_file_system_service =
    237       SyncFileSystemServiceFactory::GetForProfile(profile());
    238   for (unsigned int i = 0; i < num_expected_results_; i++) {
    239     std::string url;
    240     file_entry_urls->GetString(i, &url);
    241     fileapi::FileSystemURL file_system_url(
    242         file_system_context->CrackURL(GURL(url)));
    243 
    244     sync_file_system_service->GetFileSyncStatus(
    245         file_system_url,
    246         Bind(&SyncFileSystemGetFileStatusesFunction::DidGetFileStatus,
    247              this, file_system_url));
    248   }
    249 
    250   return true;
    251 }
    252 
    253 void SyncFileSystemGetFileStatusesFunction::DidGetFileStatus(
    254     const fileapi::FileSystemURL& file_system_url,
    255     SyncStatusCode sync_status_code,
    256     SyncFileStatus sync_file_status) {
    257   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    258   num_results_received_++;
    259   DCHECK_LE(num_results_received_, num_expected_results_);
    260 
    261   file_sync_statuses_[file_system_url] =
    262       std::make_pair(sync_status_code, sync_file_status);
    263 
    264   // Keep mapping file statuses until all of them have been received.
    265   // TODO(calvinlo): Get rid of this check when batch version of
    266   // GetFileSyncStatus(GURL urls[]); is added.
    267   if (num_results_received_ < num_expected_results_)
    268     return;
    269 
    270   // All results received. Dump array of statuses into extension enum values.
    271   // Note that the enum types need to be set as strings manually as the
    272   // autogenerated Results::Create function thinks the enum values should be
    273   // returned as int values.
    274   base::ListValue* status_array = new base::ListValue();
    275   for (URLToStatusMap::iterator it = file_sync_statuses_.begin();
    276        it != file_sync_statuses_.end(); ++it) {
    277     base::DictionaryValue* dict = new base::DictionaryValue();
    278     status_array->Append(dict);
    279 
    280     fileapi::FileSystemURL url = it->first;
    281     SyncStatusCode file_error = it->second.first;
    282     api::sync_file_system::FileStatus file_status =
    283         SyncFileStatusToExtensionEnum(it->second.second);
    284 
    285     dict->Set("entry", CreateDictionaryValueForFileSystemEntry(
    286         url, sync_file_system::SYNC_FILE_TYPE_FILE));
    287     dict->SetString("status", ToString(file_status));
    288 
    289     if (file_error == sync_file_system::SYNC_STATUS_OK)
    290       continue;
    291     dict->SetString("error",
    292                     sync_file_system::SyncStatusCodeToString(file_error));
    293   }
    294   SetResult(status_array);
    295 
    296   SendResponse(true);
    297 }
    298 
    299 bool SyncFileSystemGetUsageAndQuotaFunction::RunImpl() {
    300   std::string url;
    301   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
    302 
    303   scoped_refptr<fileapi::FileSystemContext> file_system_context =
    304       BrowserContext::GetStoragePartition(
    305           profile(),
    306           render_view_host()->GetSiteInstance())->GetFileSystemContext();
    307   fileapi::FileSystemURL file_system_url(
    308       file_system_context->CrackURL(GURL(url)));
    309 
    310   scoped_refptr<quota::QuotaManager> quota_manager =
    311       BrowserContext::GetStoragePartition(
    312           profile(),
    313           render_view_host()->GetSiteInstance())->GetQuotaManager();
    314 
    315   BrowserThread::PostTask(
    316       BrowserThread::IO,
    317       FROM_HERE,
    318       Bind(&quota::QuotaManager::GetUsageAndQuotaForWebApps,
    319            quota_manager,
    320            source_url().GetOrigin(),
    321            fileapi::FileSystemTypeToQuotaStorageType(file_system_url.type()),
    322            Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota,
    323                 this)));
    324 
    325   return true;
    326 }
    327 
    328 void SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota(
    329       quota::QuotaStatusCode status, int64 usage, int64 quota) {
    330   // Repost to switch from IO thread to UI thread for SendResponse().
    331   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    332     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    333     BrowserThread::PostTask(
    334         BrowserThread::UI,
    335         FROM_HERE,
    336         Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota, this,
    337              status, usage, quota));
    338     return;
    339   }
    340 
    341   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    342   if (status != quota::kQuotaStatusOk) {
    343     error_ = QuotaStatusCodeToString(status);
    344     SendResponse(false);
    345     return;
    346   }
    347 
    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);
    352   SendResponse(true);
    353 }
    354 
    355 bool SyncFileSystemSetConflictResolutionPolicyFunction::RunImpl() {
    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_UNKNOWN) {
    361     SetError(base::StringPrintf(kUnsupportedConflictResolutionPolicy,
    362                                 policy_string.c_str()));
    363     return false;
    364   }
    365   sync_file_system::SyncFileSystemService* service = GetSyncFileSystemService(
    366       profile());
    367   DCHECK(service);
    368   SyncStatusCode status = service->SetConflictResolutionPolicy(policy);
    369   if (status != sync_file_system::SYNC_STATUS_OK) {
    370     SetError(sync_file_system::SyncStatusCodeToString(status));
    371     return false;
    372   }
    373   return true;
    374 }
    375 
    376 bool SyncFileSystemGetConflictResolutionPolicyFunction::RunImpl() {
    377   sync_file_system::SyncFileSystemService* service = GetSyncFileSystemService(
    378       profile());
    379   DCHECK(service);
    380   api::sync_file_system::ConflictResolutionPolicy policy =
    381       ConflictResolutionPolicyToExtensionEnum(
    382           service->GetConflictResolutionPolicy());
    383   SetResult(Value::CreateStringValue(
    384           api::sync_file_system::ToString(policy)));
    385   return true;
    386 }
    387 
    388 }  // namespace extensions
    389