Home | History | Annotate | Download | only in drive_backend
      1 // Copyright 2013 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/sync_file_system/drive_backend/drive_backend_util.h"
      6 
      7 #include "base/file_util.h"
      8 #include "base/logging.h"
      9 #include "base/memory/scoped_vector.h"
     10 #include "base/message_loop/message_loop_proxy.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "chrome/browser/drive/drive_api_util.h"
     13 #include "chrome/browser/sync_file_system/drive_backend/drive_backend_constants.h"
     14 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
     15 #include "chrome/browser/sync_file_system/logger.h"
     16 #include "google_apis/drive/drive_api_parser.h"
     17 #include "google_apis/drive/gdata_wapi_parser.h"
     18 #include "net/base/mime_util.h"
     19 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
     20 
     21 namespace sync_file_system {
     22 namespace drive_backend {
     23 
     24 void PutServiceMetadataToBatch(const ServiceMetadata& service_metadata,
     25                                leveldb::WriteBatch* batch) {
     26   std::string value;
     27   bool success = service_metadata.SerializeToString(&value);
     28   DCHECK(success);
     29   batch->Put(kServiceMetadataKey, value);
     30 }
     31 
     32 void PutFileMetadataToBatch(const FileMetadata& file,
     33                             leveldb::WriteBatch* batch) {
     34   if (!batch)
     35     return;
     36 
     37   std::string value;
     38   bool success = file.SerializeToString(&value);
     39   DCHECK(success);
     40   batch->Put(kFileMetadataKeyPrefix + file.file_id(), value);
     41 }
     42 
     43 void PutFileTrackerToBatch(const FileTracker& tracker,
     44                            leveldb::WriteBatch* batch) {
     45   if (!batch)
     46     return;
     47 
     48   std::string value;
     49   bool success = tracker.SerializeToString(&value);
     50   DCHECK(success);
     51   batch->Put(kFileTrackerKeyPrefix + base::Int64ToString(tracker.tracker_id()),
     52              value);
     53 }
     54 
     55 void PutFileMetadataDeletionToBatch(const std::string& file_id,
     56                                     leveldb::WriteBatch* batch) {
     57   if (batch)
     58     batch->Delete(kFileMetadataKeyPrefix + file_id);
     59 }
     60 
     61 void PutFileTrackerDeletionToBatch(int64 tracker_id,
     62                                    leveldb::WriteBatch* batch) {
     63   if (batch)
     64     batch->Delete(kFileTrackerKeyPrefix + base::Int64ToString(tracker_id));
     65 }
     66 
     67 void PopulateFileDetailsByFileResource(
     68     const google_apis::FileResource& file_resource,
     69     FileDetails* details) {
     70   details->clear_parent_folder_ids();
     71   for (std::vector<google_apis::ParentReference>::const_iterator itr =
     72            file_resource.parents().begin();
     73        itr != file_resource.parents().end();
     74        ++itr) {
     75     details->add_parent_folder_ids(itr->file_id());
     76   }
     77   details->set_title(file_resource.title());
     78 
     79   google_apis::DriveEntryKind kind = drive::util::GetKind(file_resource);
     80   if (kind == google_apis::ENTRY_KIND_FILE)
     81     details->set_file_kind(FILE_KIND_FILE);
     82   else if (kind == google_apis::ENTRY_KIND_FOLDER)
     83     details->set_file_kind(FILE_KIND_FOLDER);
     84   else
     85     details->set_file_kind(FILE_KIND_UNSUPPORTED);
     86 
     87   details->set_md5(file_resource.md5_checksum());
     88   details->set_etag(file_resource.etag());
     89   details->set_creation_time(file_resource.created_date().ToInternalValue());
     90   details->set_modification_time(
     91       file_resource.modified_date().ToInternalValue());
     92   details->set_missing(file_resource.labels().is_trashed());
     93 }
     94 
     95 scoped_ptr<FileMetadata> CreateFileMetadataFromFileResource(
     96     int64 change_id,
     97     const google_apis::FileResource& resource) {
     98   scoped_ptr<FileMetadata> file(new FileMetadata);
     99   file->set_file_id(resource.file_id());
    100 
    101   FileDetails* details = file->mutable_details();
    102   details->set_change_id(change_id);
    103 
    104   if (resource.labels().is_trashed()) {
    105     details->set_missing(true);
    106     return file.Pass();
    107   }
    108 
    109   PopulateFileDetailsByFileResource(resource, details);
    110   return file.Pass();
    111 }
    112 
    113 scoped_ptr<FileMetadata> CreateFileMetadataFromChangeResource(
    114     const google_apis::ChangeResource& change) {
    115   scoped_ptr<FileMetadata> file(new FileMetadata);
    116   file->set_file_id(change.file_id());
    117 
    118   FileDetails* details = file->mutable_details();
    119   details->set_change_id(change.change_id());
    120 
    121   if (change.is_deleted()) {
    122     details->set_missing(true);
    123     return file.Pass();
    124   }
    125 
    126   PopulateFileDetailsByFileResource(*change.file(), details);
    127   return file.Pass();
    128 }
    129 
    130 scoped_ptr<FileMetadata> CreateDeletedFileMetadata(
    131     int64 change_id,
    132     const std::string& file_id) {
    133   scoped_ptr<FileMetadata> file(new FileMetadata);
    134   file->set_file_id(file_id);
    135 
    136   FileDetails* details = file->mutable_details();
    137   details->set_change_id(change_id);
    138   details->set_missing(true);
    139   return file.Pass();
    140 }
    141 
    142 webkit_blob::ScopedFile CreateTemporaryFile(
    143     base::TaskRunner* file_task_runner) {
    144   base::FilePath temp_file_path;
    145   if (!base::CreateTemporaryFile(&temp_file_path))
    146     return webkit_blob::ScopedFile();
    147 
    148   return webkit_blob::ScopedFile(
    149       temp_file_path,
    150       webkit_blob::ScopedFile::DELETE_ON_SCOPE_OUT,
    151       file_task_runner);
    152 }
    153 
    154 std::string FileKindToString(FileKind file_kind) {
    155   switch (file_kind) {
    156     case FILE_KIND_UNSUPPORTED:
    157       return "unsupported";
    158     case FILE_KIND_FILE:
    159       return "file";
    160     case FILE_KIND_FOLDER:
    161       return "folder";
    162   }
    163 
    164   NOTREACHED();
    165   return "unknown";
    166 }
    167 
    168 bool HasFileAsParent(const FileDetails& details, const std::string& file_id) {
    169   for (int i = 0; i < details.parent_folder_ids_size(); ++i) {
    170     if (details.parent_folder_ids(i) == file_id)
    171       return true;
    172   }
    173   return false;
    174 }
    175 
    176 std::string GetMimeTypeFromTitle(const base::FilePath& title) {
    177   base::FilePath::StringType extension = title.Extension();
    178   std::string mime_type;
    179   if (extension.empty() ||
    180       !net::GetWellKnownMimeTypeFromExtension(extension.substr(1), &mime_type))
    181     return kMimeTypeOctetStream;
    182   return mime_type;
    183 }
    184 
    185 SyncStatusCode GDataErrorCodeToSyncStatusCode(
    186     google_apis::GDataErrorCode error) {
    187   // NOTE: Please update DriveFileSyncService::UpdateServiceState when you add
    188   // more error code mapping.
    189   switch (error) {
    190     case google_apis::HTTP_SUCCESS:
    191     case google_apis::HTTP_CREATED:
    192     case google_apis::HTTP_NO_CONTENT:
    193     case google_apis::HTTP_FOUND:
    194       return SYNC_STATUS_OK;
    195 
    196     case google_apis::HTTP_NOT_MODIFIED:
    197       return SYNC_STATUS_NOT_MODIFIED;
    198 
    199     case google_apis::HTTP_CONFLICT:
    200     case google_apis::HTTP_PRECONDITION:
    201       return SYNC_STATUS_HAS_CONFLICT;
    202 
    203     case google_apis::HTTP_UNAUTHORIZED:
    204       return SYNC_STATUS_AUTHENTICATION_FAILED;
    205 
    206     case google_apis::GDATA_NO_CONNECTION:
    207       return SYNC_STATUS_NETWORK_ERROR;
    208 
    209     case google_apis::HTTP_INTERNAL_SERVER_ERROR:
    210     case google_apis::HTTP_BAD_GATEWAY:
    211     case google_apis::HTTP_SERVICE_UNAVAILABLE:
    212     case google_apis::GDATA_CANCELLED:
    213     case google_apis::GDATA_NOT_READY:
    214       return SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE;
    215 
    216     case google_apis::HTTP_NOT_FOUND:
    217     case google_apis::HTTP_GONE:
    218       return SYNC_FILE_ERROR_NOT_FOUND;
    219 
    220     case google_apis::GDATA_FILE_ERROR:
    221       return SYNC_FILE_ERROR_FAILED;
    222 
    223     case google_apis::HTTP_FORBIDDEN:
    224       return SYNC_STATUS_ACCESS_FORBIDDEN;
    225 
    226     case google_apis::HTTP_RESUME_INCOMPLETE:
    227     case google_apis::HTTP_BAD_REQUEST:
    228     case google_apis::HTTP_LENGTH_REQUIRED:
    229     case google_apis::HTTP_NOT_IMPLEMENTED:
    230     case google_apis::GDATA_PARSE_ERROR:
    231     case google_apis::GDATA_OTHER_ERROR:
    232       return SYNC_STATUS_FAILED;
    233 
    234     case google_apis::GDATA_NO_SPACE:
    235       return SYNC_FILE_ERROR_NO_SPACE;
    236   }
    237 
    238   // There's a case where DriveService layer returns GDataErrorCode==-1
    239   // when network is unavailable. (http://crbug.com/223042)
    240   // TODO(kinuko,nhiroki): We should identify from where this undefined error
    241   // code is coming.
    242   if (error == -1)
    243     return SYNC_STATUS_NETWORK_ERROR;
    244 
    245   util::Log(logging::LOG_WARNING,
    246             FROM_HERE,
    247             "Got unexpected error: %d",
    248             static_cast<int>(error));
    249   return SYNC_STATUS_FAILED;
    250 }
    251 
    252 scoped_ptr<FileTracker> CloneFileTracker(const FileTracker* obj) {
    253   if (!obj)
    254     return scoped_ptr<FileTracker>();
    255   return scoped_ptr<FileTracker>(new FileTracker(*obj));
    256 }
    257 
    258 }  // namespace drive_backend
    259 }  // namespace sync_file_system
    260