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