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