media_file_system_backend.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
1// Copyright (c) 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/media_galleries/fileapi/media_file_system_backend.h" 6 7#include <string> 8 9#include "base/bind.h" 10#include "base/files/file_path.h" 11#include "base/logging.h" 12#include "base/message_loop/message_loop_proxy.h" 13#include "base/sequenced_task_runner.h" 14#include "base/strings/string_number_conversions.h" 15#include "base/strings/string_util.h" 16#include "base/strings/utf_string_conversions.h" 17#include "base/threading/sequenced_worker_pool.h" 18#include "chrome/browser/browser_process.h" 19#include "chrome/browser/extensions/extension_service.h" 20#include "chrome/browser/media_galleries/fileapi/device_media_async_file_util.h" 21#include "chrome/browser/media_galleries/fileapi/media_file_validator_factory.h" 22#include "chrome/browser/media_galleries/fileapi/media_path_filter.h" 23#include "chrome/browser/media_galleries/fileapi/native_media_file_util.h" 24#include "chrome/browser/media_galleries/media_file_system_registry.h" 25#include "chrome/browser/profiles/profile.h" 26#include "content/public/browser/browser_thread.h" 27#include "content/public/browser/render_process_host.h" 28#include "content/public/browser/render_view_host.h" 29#include "content/public/browser/resource_request_info.h" 30#include "extensions/browser/extension_system.h" 31#include "net/url_request/url_request.h" 32#include "webkit/browser/blob/file_stream_reader.h" 33#include "webkit/browser/fileapi/copy_or_move_file_validator.h" 34#include "webkit/browser/fileapi/file_stream_writer.h" 35#include "webkit/browser/fileapi/file_system_context.h" 36#include "webkit/browser/fileapi/file_system_operation.h" 37#include "webkit/browser/fileapi/file_system_operation_context.h" 38#include "webkit/browser/fileapi/file_system_url.h" 39#include "webkit/browser/fileapi/native_file_util.h" 40#include "webkit/common/fileapi/file_system_types.h" 41#include "webkit/common/fileapi/file_system_util.h" 42 43#if defined(OS_WIN) || defined(OS_MACOSX) 44#include "chrome/browser/media_galleries/fileapi/itunes_file_util.h" 45#include "chrome/browser/media_galleries/fileapi/picasa_file_util.h" 46#endif // defined(OS_WIN) || defined(OS_MACOSX) 47 48#if defined(OS_MACOSX) 49#include "chrome/browser/media_galleries/fileapi/iphoto_file_util.h" 50#endif // defined(OS_MACOSX) 51 52using storage::FileSystemContext; 53using storage::FileSystemURL; 54 55namespace { 56 57const char kMediaGalleryMountPrefix[] = "media_galleries-"; 58 59void OnPreferencesInit( 60 const content::RenderViewHost* rvh, 61 const extensions::Extension* extension, 62 MediaGalleryPrefId pref_id, 63 const base::Callback<void(base::File::Error result)>& callback) { 64 MediaFileSystemRegistry* registry = 65 g_browser_process->media_file_system_registry(); 66 registry->RegisterMediaFileSystemForExtension(rvh, extension, pref_id, 67 callback); 68} 69 70void AttemptAutoMountOnUIThread( 71 int32 process_id, 72 int32 routing_id, 73 const std::string& storage_domain, 74 const std::string& mount_point, 75 const base::Callback<void(base::File::Error result)>& callback) { 76 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 77 78 content::RenderViewHost* rvh = 79 content::RenderViewHost::FromID(process_id, routing_id); 80 if (rvh) { 81 Profile* profile = 82 Profile::FromBrowserContext(rvh->GetProcess()->GetBrowserContext()); 83 84 ExtensionService* extension_service = 85 extensions::ExtensionSystem::Get(profile)->extension_service(); 86 const extensions::Extension* extension = 87 extension_service->GetExtensionById(storage_domain, 88 false /*include disabled*/); 89 std::string expected_mount_prefix = 90 MediaFileSystemBackend::ConstructMountName( 91 profile->GetPath(), storage_domain, kInvalidMediaGalleryPrefId); 92 MediaGalleryPrefId pref_id = kInvalidMediaGalleryPrefId; 93 if (extension && 94 extension->id() == storage_domain && 95 StartsWithASCII(mount_point, expected_mount_prefix, true) && 96 base::StringToUint64(mount_point.substr(expected_mount_prefix.size()), 97 &pref_id) && 98 pref_id != kInvalidMediaGalleryPrefId) { 99 MediaGalleriesPreferences* preferences = 100 g_browser_process->media_file_system_registry()->GetPreferences( 101 profile); 102 preferences->EnsureInitialized( 103 base::Bind(&OnPreferencesInit, rvh, extension, pref_id, callback)); 104 return; 105 } 106 } 107 108 content::BrowserThread::PostTask( 109 content::BrowserThread::IO, 110 FROM_HERE, 111 base::Bind(callback, base::File::FILE_ERROR_NOT_FOUND)); 112} 113 114} // namespace 115 116const char MediaFileSystemBackend::kMediaTaskRunnerName[] = 117 "media-task-runner"; 118 119MediaFileSystemBackend::MediaFileSystemBackend( 120 const base::FilePath& profile_path, 121 base::SequencedTaskRunner* media_task_runner) 122 : profile_path_(profile_path), 123 media_task_runner_(media_task_runner), 124 media_path_filter_(new MediaPathFilter), 125 media_copy_or_move_file_validator_factory_(new MediaFileValidatorFactory), 126 native_media_file_util_( 127 new NativeMediaFileUtil(media_path_filter_.get())), 128 device_media_async_file_util_( 129 DeviceMediaAsyncFileUtil::Create(profile_path_, 130 APPLY_MEDIA_FILE_VALIDATION)) 131#if defined(OS_WIN) || defined(OS_MACOSX) 132 , 133 picasa_file_util_(new picasa::PicasaFileUtil(media_path_filter_.get())), 134 itunes_file_util_(new itunes::ITunesFileUtil(media_path_filter_.get())) 135#endif // defined(OS_WIN) || defined(OS_MACOSX) 136#if defined(OS_MACOSX) 137 , 138 iphoto_file_util_(new iphoto::IPhotoFileUtil(media_path_filter_.get())) 139#endif // defined(OS_MACOSX) 140{ 141} 142 143MediaFileSystemBackend::~MediaFileSystemBackend() { 144} 145 146// static 147bool MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread() { 148 base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool(); 149 base::SequencedWorkerPool::SequenceToken media_sequence_token = 150 pool->GetNamedSequenceToken(kMediaTaskRunnerName); 151 return pool->IsRunningSequenceOnCurrentThread(media_sequence_token); 152} 153 154// static 155scoped_refptr<base::SequencedTaskRunner> 156MediaFileSystemBackend::MediaTaskRunner() { 157 base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool(); 158 base::SequencedWorkerPool::SequenceToken media_sequence_token = 159 pool->GetNamedSequenceToken(kMediaTaskRunnerName); 160 return pool->GetSequencedTaskRunner(media_sequence_token); 161} 162 163// static 164std::string MediaFileSystemBackend::ConstructMountName( 165 const base::FilePath& profile_path, 166 const std::string& extension_id, 167 MediaGalleryPrefId pref_id) { 168 std::string name(kMediaGalleryMountPrefix); 169 name.append(profile_path.BaseName().MaybeAsASCII()); 170 name.append("-"); 171 name.append(extension_id); 172 name.append("-"); 173 if (pref_id != kInvalidMediaGalleryPrefId) 174 name.append(base::Uint64ToString(pref_id)); 175 base::ReplaceChars(name, " /", "_", &name); 176 return name; 177} 178 179// static 180bool MediaFileSystemBackend::AttemptAutoMountForURLRequest( 181 const net::URLRequest* url_request, 182 const storage::FileSystemURL& filesystem_url, 183 const std::string& storage_domain, 184 const base::Callback<void(base::File::Error result)>& callback) { 185 if (storage_domain.empty() || 186 filesystem_url.type() != storage::kFileSystemTypeExternal || 187 storage_domain != filesystem_url.origin().host()) { 188 return false; 189 } 190 191 const base::FilePath& virtual_path = filesystem_url.path(); 192 if (virtual_path.ReferencesParent()) 193 return false; 194 std::vector<base::FilePath::StringType> components; 195 virtual_path.GetComponents(&components); 196 if (components.empty()) 197 return false; 198 std::string mount_point = base::FilePath(components[0]).AsUTF8Unsafe(); 199 if (!StartsWithASCII(mount_point, kMediaGalleryMountPrefix, true)) 200 return false; 201 202 const content::ResourceRequestInfo* request_info = 203 content::ResourceRequestInfo::ForRequest(url_request); 204 if (!request_info) 205 return false; 206 207 content::BrowserThread::PostTask( 208 content::BrowserThread::UI, 209 FROM_HERE, 210 base::Bind(&AttemptAutoMountOnUIThread, request_info->GetChildID(), 211 request_info->GetRouteID(), storage_domain, mount_point, 212 callback)); 213 return true; 214} 215 216bool MediaFileSystemBackend::CanHandleType(storage::FileSystemType type) const { 217 switch (type) { 218 case storage::kFileSystemTypeNativeMedia: 219 case storage::kFileSystemTypeDeviceMedia: 220#if defined(OS_WIN) || defined(OS_MACOSX) 221 case storage::kFileSystemTypePicasa: 222 case storage::kFileSystemTypeItunes: 223#endif // defined(OS_WIN) || defined(OS_MACOSX) 224#if defined(OS_MACOSX) 225 case storage::kFileSystemTypeIphoto: 226#endif // defined(OS_MACOSX) 227 return true; 228 default: 229 return false; 230 } 231} 232 233void MediaFileSystemBackend::Initialize(storage::FileSystemContext* context) { 234} 235 236void MediaFileSystemBackend::ResolveURL( 237 const FileSystemURL& url, 238 storage::OpenFileSystemMode mode, 239 const OpenFileSystemCallback& callback) { 240 // We never allow opening a new FileSystem via usual ResolveURL. 241 base::MessageLoopProxy::current()->PostTask( 242 FROM_HERE, 243 base::Bind(callback, 244 GURL(), 245 std::string(), 246 base::File::FILE_ERROR_SECURITY)); 247} 248 249storage::AsyncFileUtil* MediaFileSystemBackend::GetAsyncFileUtil( 250 storage::FileSystemType type) { 251 switch (type) { 252 case storage::kFileSystemTypeNativeMedia: 253 return native_media_file_util_.get(); 254 case storage::kFileSystemTypeDeviceMedia: 255 return device_media_async_file_util_.get(); 256#if defined(OS_WIN) || defined(OS_MACOSX) 257 case storage::kFileSystemTypeItunes: 258 return itunes_file_util_.get(); 259 case storage::kFileSystemTypePicasa: 260 return picasa_file_util_.get(); 261#endif // defined(OS_WIN) || defined(OS_MACOSX) 262#if defined(OS_MACOSX) 263 case storage::kFileSystemTypeIphoto: 264 return iphoto_file_util_.get(); 265#endif // defined(OS_MACOSX) 266 default: 267 NOTREACHED(); 268 } 269 return NULL; 270} 271 272storage::CopyOrMoveFileValidatorFactory* 273MediaFileSystemBackend::GetCopyOrMoveFileValidatorFactory( 274 storage::FileSystemType type, 275 base::File::Error* error_code) { 276 DCHECK(error_code); 277 *error_code = base::File::FILE_OK; 278 switch (type) { 279 case storage::kFileSystemTypeNativeMedia: 280 case storage::kFileSystemTypeDeviceMedia: 281 case storage::kFileSystemTypeIphoto: 282 case storage::kFileSystemTypeItunes: 283 if (!media_copy_or_move_file_validator_factory_) { 284 *error_code = base::File::FILE_ERROR_SECURITY; 285 return NULL; 286 } 287 return media_copy_or_move_file_validator_factory_.get(); 288 default: 289 NOTREACHED(); 290 } 291 return NULL; 292} 293 294storage::FileSystemOperation* MediaFileSystemBackend::CreateFileSystemOperation( 295 const FileSystemURL& url, 296 FileSystemContext* context, 297 base::File::Error* error_code) const { 298 scoped_ptr<storage::FileSystemOperationContext> operation_context( 299 new storage::FileSystemOperationContext(context, 300 media_task_runner_.get())); 301 return storage::FileSystemOperation::Create( 302 url, context, operation_context.Pass()); 303} 304 305bool MediaFileSystemBackend::SupportsStreaming( 306 const storage::FileSystemURL& url) const { 307 if (url.type() == storage::kFileSystemTypeDeviceMedia) { 308 DCHECK(device_media_async_file_util_); 309 return device_media_async_file_util_->SupportsStreaming(url); 310 } 311 312 return false; 313} 314 315bool MediaFileSystemBackend::HasInplaceCopyImplementation( 316 storage::FileSystemType type) const { 317 DCHECK(type == storage::kFileSystemTypeNativeMedia || 318 type == storage::kFileSystemTypeDeviceMedia || 319 type == storage::kFileSystemTypeItunes || 320 type == storage::kFileSystemTypePicasa || 321 type == storage::kFileSystemTypeIphoto); 322 return true; 323} 324 325scoped_ptr<storage::FileStreamReader> 326MediaFileSystemBackend::CreateFileStreamReader( 327 const FileSystemURL& url, 328 int64 offset, 329 const base::Time& expected_modification_time, 330 FileSystemContext* context) const { 331 if (url.type() == storage::kFileSystemTypeDeviceMedia) { 332 DCHECK(device_media_async_file_util_); 333 scoped_ptr<storage::FileStreamReader> reader = 334 device_media_async_file_util_->GetFileStreamReader( 335 url, offset, expected_modification_time, context); 336 DCHECK(reader); 337 return reader.Pass(); 338 } 339 340 return scoped_ptr<storage::FileStreamReader>( 341 storage::FileStreamReader::CreateForLocalFile( 342 context->default_file_task_runner(), 343 url.path(), 344 offset, 345 expected_modification_time)); 346} 347 348scoped_ptr<storage::FileStreamWriter> 349MediaFileSystemBackend::CreateFileStreamWriter( 350 const FileSystemURL& url, 351 int64 offset, 352 FileSystemContext* context) const { 353 return scoped_ptr<storage::FileStreamWriter>( 354 storage::FileStreamWriter::CreateForLocalFile( 355 context->default_file_task_runner(), 356 url.path(), 357 offset, 358 storage::FileStreamWriter::OPEN_EXISTING_FILE)); 359} 360 361storage::FileSystemQuotaUtil* MediaFileSystemBackend::GetQuotaUtil() { 362 // No quota support. 363 return NULL; 364} 365