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/chromeos/drive/resource_entry_conversion.h" 6 7 #include <algorithm> 8 #include <string> 9 10 #include "base/logging.h" 11 #include "base/platform_file.h" 12 #include "base/time/time.h" 13 #include "chrome/browser/chromeos/drive/drive.pb.h" 14 #include "chrome/browser/chromeos/drive/file_system_util.h" 15 #include "chrome/browser/drive/drive_api_util.h" 16 #include "google_apis/drive/gdata_wapi_parser.h" 17 18 namespace drive { 19 20 namespace { 21 22 const char kSharedWithMeLabel[] = "shared-with-me"; 23 const char kSharedLabel[] = "shared"; 24 25 // Checks if |entry| has a specified label. 26 bool HasLabel(const google_apis::ResourceEntry& entry, 27 const std::string& label) { 28 std::vector<std::string>::const_iterator it = 29 std::find(entry.labels().begin(), entry.labels().end(), label); 30 return it != entry.labels().end(); 31 } 32 33 } // namespace 34 35 bool ConvertToResourceEntry(const google_apis::ResourceEntry& input, 36 ResourceEntry* out_entry, 37 std::string* out_parent_resource_id) { 38 DCHECK(out_entry); 39 DCHECK(out_parent_resource_id); 40 41 ResourceEntry converted; 42 43 // For regular files, the 'filename' and 'title' attribute in the metadata 44 // may be different (e.g. due to rename). To be consistent with the web 45 // interface and other client to use the 'title' attribute, instead of 46 // 'filename', as the file name in the local snapshot. 47 converted.set_title(input.title()); 48 converted.set_base_name(util::NormalizeFileName(converted.title())); 49 converted.set_resource_id(input.resource_id()); 50 51 // Gets parent Resource ID. On drive.google.com, a file can have multiple 52 // parents or no parent, but we are forcing a tree-shaped structure (i.e. no 53 // multi-parent or zero-parent entries). Therefore the first found "parent" is 54 // used for the entry and if the entry has no parent, we assign a special ID 55 // which represents no-parent entries. Tracked in http://crbug.com/158904. 56 std::string parent_resource_id; 57 const google_apis::Link* parent_link = 58 input.GetLinkByType(google_apis::Link::LINK_PARENT); 59 if (parent_link) 60 parent_resource_id = util::ExtractResourceIdFromUrl(parent_link->href()); 61 62 // Apply mapping from an empty parent to the special dummy directory. 63 if (parent_resource_id.empty()) 64 parent_resource_id = util::kDriveOtherDirLocalId; 65 66 converted.set_deleted(input.deleted()); 67 converted.set_shared_with_me(HasLabel(input, kSharedWithMeLabel)); 68 converted.set_shared(HasLabel(input, kSharedLabel)); 69 70 PlatformFileInfoProto* file_info = converted.mutable_file_info(); 71 72 file_info->set_last_modified(input.updated_time().ToInternalValue()); 73 // If the file has never been viewed (last_viewed_time().is_null() == true), 74 // then we will set the last_accessed field in the protocol buffer to 0. 75 file_info->set_last_accessed(input.last_viewed_time().ToInternalValue()); 76 file_info->set_creation_time(input.published_time().ToInternalValue()); 77 78 if (input.is_file() || input.is_hosted_document()) { 79 FileSpecificInfo* file_specific_info = 80 converted.mutable_file_specific_info(); 81 if (input.is_file()) { 82 file_info->set_size(input.file_size()); 83 file_specific_info->set_md5(input.file_md5()); 84 85 // The resumable-edit-media link should only be present for regular 86 // files as hosted documents are not uploadable. 87 } else if (input.is_hosted_document()) { 88 // Attach .g<something> extension to hosted documents so we can special 89 // case their handling in UI. 90 // TODO(satorux): Figure out better way how to pass input info like kind 91 // to UI through the File API stack. 92 const std::string document_extension = input.GetHostedDocumentExtension(); 93 file_specific_info->set_document_extension(document_extension); 94 converted.set_base_name( 95 util::NormalizeFileName(converted.title() + document_extension)); 96 97 // We don't know the size of hosted docs and it does not matter since 98 // is has no effect on the quota. 99 file_info->set_size(0); 100 } 101 file_info->set_is_directory(false); 102 file_specific_info->set_content_mime_type(input.content_mime_type()); 103 file_specific_info->set_is_hosted_document(input.is_hosted_document()); 104 105 const google_apis::Link* alternate_link = 106 input.GetLinkByType(google_apis::Link::LINK_ALTERNATE); 107 if (alternate_link) 108 file_specific_info->set_alternate_url(alternate_link->href().spec()); 109 110 const int64 image_width = input.image_width(); 111 if (image_width != -1) 112 file_specific_info->set_image_width(image_width); 113 114 const int64 image_height = input.image_height(); 115 if (image_height != -1) 116 file_specific_info->set_image_height(image_height); 117 118 const int64 image_rotation = input.image_rotation(); 119 if (image_rotation != -1) 120 file_specific_info->set_image_rotation(image_rotation); 121 } else if (input.is_folder()) { 122 file_info->set_is_directory(true); 123 } else { 124 // There are two cases to reach here. 125 // * The entry is something that doesn't map into files (i.e. sites). 126 // We don't handle these kind of entries hence return false. 127 // * The entry is un-shared to you by other owner. In that case, we 128 // get an entry with only deleted() and resource_id() fields are 129 // filled. Since we want to delete such entries locally as well, 130 // in that case we need to return true to proceed. 131 if (!input.deleted()) 132 return false; 133 } 134 135 out_entry->Swap(&converted); 136 swap(*out_parent_resource_id, parent_resource_id); 137 return true; 138 } 139 140 void ConvertResourceEntryToPlatformFileInfo(const ResourceEntry& entry, 141 base::PlatformFileInfo* file_info) { 142 file_info->size = entry.file_info().size(); 143 file_info->is_directory = entry.file_info().is_directory(); 144 file_info->is_symbolic_link = entry.file_info().is_symbolic_link(); 145 file_info->last_modified = base::Time::FromInternalValue( 146 entry.file_info().last_modified()); 147 file_info->last_accessed = base::Time::FromInternalValue( 148 entry.file_info().last_accessed()); 149 file_info->creation_time = base::Time::FromInternalValue( 150 entry.file_info().creation_time()); 151 } 152 153 void SetPlatformFileInfoToResourceEntry(const base::PlatformFileInfo& file_info, 154 ResourceEntry* entry) { 155 PlatformFileInfoProto* entry_file_info = entry->mutable_file_info(); 156 entry_file_info->set_size(file_info.size); 157 entry_file_info->set_is_directory(file_info.is_directory); 158 entry_file_info->set_is_symbolic_link(file_info.is_symbolic_link); 159 entry_file_info->set_last_modified(file_info.last_modified.ToInternalValue()); 160 entry_file_info->set_last_accessed(file_info.last_accessed.ToInternalValue()); 161 entry_file_info->set_creation_time(file_info.creation_time.ToInternalValue()); 162 } 163 164 } // namespace drive 165