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/media_galleries/imported_media_gallery_registry.h"
6
7#include "base/bind.h"
8#include "base/files/file_util.h"
9#include "base/logging.h"
10#include "chrome/browser/media_galleries/fileapi/iphoto_data_provider.h"
11#include "chrome/browser/media_galleries/fileapi/itunes_data_provider.h"
12#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
13#include "chrome/browser/media_galleries/fileapi/picasa_data_provider.h"
14#include "chrome/common/extensions/extension_constants.h"
15#include "content/public/browser/browser_thread.h"
16#include "storage/browser/fileapi/external_mount_points.h"
17#include "storage/common/fileapi/file_system_mount_option.h"
18
19using base::Bind;
20using storage::ExternalMountPoints;
21
22namespace {
23
24static base::LazyInstance<ImportedMediaGalleryRegistry>::Leaky
25g_imported_media_gallery_registry = LAZY_INSTANCE_INITIALIZER;
26
27}  // namespace
28
29// static
30ImportedMediaGalleryRegistry* ImportedMediaGalleryRegistry::GetInstance() {
31  return g_imported_media_gallery_registry.Pointer();
32}
33
34void ImportedMediaGalleryRegistry::Initialize() {
35  base::ThreadRestrictions::AssertIOAllowed();
36  if (imported_root_.empty()) {
37    if (!base::CreateTemporaryFile(&imported_root_))
38      imported_root_ = base::FilePath();
39    // TODO(vandebo) Setting the permissions of |imported_root_| in CPSP to
40    // zero would be an extra step to ensure permissions are correctly
41    // enforced.
42  }
43}
44
45bool ImportedMediaGalleryRegistry::RegisterPicasaFilesystemOnUIThread(
46    const std::string& fs_name, const base::FilePath& database_path) {
47  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
48  DCHECK(!fs_name.empty());
49  DCHECK(!database_path.empty());
50
51  bool result = false;
52
53#if defined(OS_WIN) || defined(OS_MACOSX)
54  base::FilePath root = ImportedRoot();
55  if (root.empty())
56    return false;
57  result = ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
58      fs_name,
59      storage::kFileSystemTypePicasa,
60      storage::FileSystemMountOption(),
61      root.AppendASCII("picasa"));
62  if (!result)
63    return result;
64
65  picasa_fs_names_.insert(fs_name);
66
67  if (picasa_fs_names_.size() == 1) {
68    MediaFileSystemBackend::MediaTaskRunner()->PostTask(
69        FROM_HERE,
70        Bind(&ImportedMediaGalleryRegistry::RegisterPicasaFileSystem,
71             base::Unretained(this), database_path));
72#ifndef NDEBUG
73    picasa_database_path_ = database_path;
74  } else {
75    DCHECK_EQ(picasa_database_path_.value(), database_path.value());
76#endif
77  }
78#endif  // defined(OS_WIN) || defined(OS_MACOSX)
79
80  return result;
81}
82
83bool ImportedMediaGalleryRegistry::RegisterITunesFilesystemOnUIThread(
84    const std::string& fs_name, const base::FilePath& library_xml_path) {
85  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
86  DCHECK(!library_xml_path.empty());
87
88  bool result = false;
89
90#if defined(OS_WIN) || defined(OS_MACOSX)
91  base::FilePath root = ImportedRoot();
92  if (root.empty())
93    return false;
94  result = ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
95      fs_name,
96      storage::kFileSystemTypeItunes,
97      storage::FileSystemMountOption(),
98      root.AppendASCII("itunes"));
99  if (!result)
100    return result;
101
102  itunes_fs_names_.insert(fs_name);
103
104  if (itunes_fs_names_.size() == 1) {
105    MediaFileSystemBackend::MediaTaskRunner()->PostTask(
106        FROM_HERE,
107        Bind(&ImportedMediaGalleryRegistry::RegisterITunesFileSystem,
108             base::Unretained(this), library_xml_path));
109#ifndef NDEBUG
110    itunes_xml_library_path_ = library_xml_path;
111  } else {
112    DCHECK_EQ(itunes_xml_library_path_.value(), library_xml_path.value());
113#endif
114  }
115#endif  // defined(OS_WIN) || defined(OS_MACOSX)
116
117  return result;
118}
119
120bool ImportedMediaGalleryRegistry::RegisterIPhotoFilesystemOnUIThread(
121    const std::string& fs_name, const base::FilePath& library_xml_path) {
122  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
123  DCHECK(!library_xml_path.empty());
124
125  bool result = false;
126
127  // TODO(gbillock): Investigate how to refactor this to reduce duplicated
128  // code.
129#if defined(OS_MACOSX)
130  base::FilePath root = ImportedRoot();
131  if (root.empty())
132    return false;
133  result = ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
134      fs_name,
135      storage::kFileSystemTypeIphoto,
136      storage::FileSystemMountOption(),
137      root.AppendASCII("iphoto"));
138  if (!result)
139    return result;
140
141  iphoto_fs_names_.insert(fs_name);
142
143  if (iphoto_fs_names_.size() == 1) {
144    MediaFileSystemBackend::MediaTaskRunner()->PostTask(
145        FROM_HERE,
146        Bind(&ImportedMediaGalleryRegistry::RegisterIPhotoFileSystem,
147             base::Unretained(this), library_xml_path));
148#ifndef NDEBUG
149    iphoto_xml_library_path_ = library_xml_path;
150  } else {
151    DCHECK_EQ(iphoto_xml_library_path_.value(), library_xml_path.value());
152#endif
153  }
154#endif  // defined(OS_MACOSX)
155
156  return result;
157}
158
159bool ImportedMediaGalleryRegistry::RevokeImportedFilesystemOnUIThread(
160    const std::string& fs_name) {
161  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
162
163#if defined(OS_WIN) || defined(OS_MACOSX)
164  if (picasa_fs_names_.erase(fs_name)) {
165    if (picasa_fs_names_.empty()) {
166      MediaFileSystemBackend::MediaTaskRunner()->PostTask(
167          FROM_HERE,
168          Bind(&ImportedMediaGalleryRegistry::RevokePicasaFileSystem,
169               base::Unretained(this)));
170    }
171    return ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(fs_name);
172  }
173
174  if (itunes_fs_names_.erase(fs_name)) {
175    if (itunes_fs_names_.empty()) {
176      MediaFileSystemBackend::MediaTaskRunner()->PostTask(
177          FROM_HERE,
178          Bind(&ImportedMediaGalleryRegistry::RevokeITunesFileSystem,
179               base::Unretained(this)));
180    }
181    return ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(fs_name);
182  }
183#endif  // defined(OS_WIN) || defined(OS_MACOSX)
184
185#if defined(OS_MACOSX)
186  if (iphoto_fs_names_.erase(fs_name)) {
187    if (iphoto_fs_names_.empty()) {
188      MediaFileSystemBackend::MediaTaskRunner()->PostTask(
189          FROM_HERE,
190          Bind(&ImportedMediaGalleryRegistry::RevokeIPhotoFileSystem,
191               base::Unretained(this)));
192    }
193    return ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(fs_name);
194  }
195#endif  // defined(OS_MACOSX)
196
197  return false;
198}
199
200base::FilePath ImportedMediaGalleryRegistry::ImportedRoot() {
201  DCHECK(!imported_root_.empty());
202  return imported_root_;
203}
204
205#if defined(OS_WIN) || defined(OS_MACOSX)
206// static
207picasa::PicasaDataProvider*
208ImportedMediaGalleryRegistry::PicasaDataProvider() {
209  DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
210  DCHECK(GetInstance()->picasa_data_provider_);
211  return GetInstance()->picasa_data_provider_.get();
212}
213
214// static
215itunes::ITunesDataProvider*
216ImportedMediaGalleryRegistry::ITunesDataProvider() {
217  DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
218  DCHECK(GetInstance()->itunes_data_provider_);
219  return GetInstance()->itunes_data_provider_.get();
220}
221#endif  // defined(OS_WIN) || defined(OS_MACOSX)
222
223#if defined(OS_MACOSX)
224// static
225iphoto::IPhotoDataProvider*
226ImportedMediaGalleryRegistry::IPhotoDataProvider() {
227  DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
228  DCHECK(GetInstance()->iphoto_data_provider_);
229  return GetInstance()->iphoto_data_provider_.get();
230}
231#endif  // defined(OS_MACOSX)
232
233ImportedMediaGalleryRegistry::ImportedMediaGalleryRegistry() {}
234
235ImportedMediaGalleryRegistry::~ImportedMediaGalleryRegistry() {
236  if (!imported_root_.empty())
237    base::DeleteFile(imported_root_, false);
238#if defined(OS_WIN) || defined(OS_MACOSX)
239  DCHECK_EQ(0U, picasa_fs_names_.size());
240  DCHECK_EQ(0U, itunes_fs_names_.size());
241#endif  // defined(OS_WIN) || defined(OS_MACOSX)
242#if defined(OS_MACOSX)
243  DCHECK_EQ(0U, iphoto_fs_names_.size());
244#endif  // defined(OS_MACOSX)
245}
246
247#if defined(OS_WIN) || defined(OS_MACOSX)
248void ImportedMediaGalleryRegistry::RegisterPicasaFileSystem(
249    const base::FilePath& database_path) {
250  DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
251  DCHECK(!picasa_data_provider_);
252  picasa_data_provider_.reset(new picasa::PicasaDataProvider(database_path));
253}
254
255void ImportedMediaGalleryRegistry::RevokePicasaFileSystem() {
256  DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
257  DCHECK(picasa_data_provider_);
258  picasa_data_provider_.reset();
259}
260
261void ImportedMediaGalleryRegistry::RegisterITunesFileSystem(
262    const base::FilePath& xml_library_path) {
263  DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
264  DCHECK(!itunes_data_provider_);
265  itunes_data_provider_.reset(new itunes::ITunesDataProvider(xml_library_path));
266}
267
268void ImportedMediaGalleryRegistry::RevokeITunesFileSystem() {
269  DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
270  DCHECK(itunes_data_provider_);
271  itunes_data_provider_.reset();
272}
273#endif  // defined(OS_WIN) || defined(OS_MACOSX)
274
275#if defined(OS_MACOSX)
276void ImportedMediaGalleryRegistry::RegisterIPhotoFileSystem(
277    const base::FilePath& xml_library_path) {
278  DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
279  DCHECK(!iphoto_data_provider_);
280  iphoto_data_provider_.reset(new iphoto::IPhotoDataProvider(xml_library_path));
281}
282
283void ImportedMediaGalleryRegistry::RevokeIPhotoFileSystem() {
284  DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
285  DCHECK(iphoto_data_provider_);
286  iphoto_data_provider_.reset();
287}
288#endif  // defined(OS_MACOSX)
289