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.
5 #include "chrome/browser/media_galleries/fileapi/iphoto_file_util.h"
11 #include "base/bind_helpers.h"
12 #include "base/files/file_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/browser/media_galleries/fileapi/iphoto_data_provider.h"
16 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
17 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "storage/browser/blob/shareable_file_reference.h"
20 #include "storage/browser/fileapi/file_system_operation_context.h"
21 #include "storage/browser/fileapi/file_system_url.h"
22 #include "storage/browser/fileapi/native_file_util.h"
23 #include "storage/common/fileapi/directory_entry.h"
24 #include "storage/common/fileapi/file_system_util.h"
26 using storage::DirectoryEntry
;
32 base::File::Error
MakeDirectoryFileInfo(base::File::Info
* file_info
) {
33 base::File::Info result
;
34 result
.is_directory
= true;
36 return base::File::FILE_OK
;
40 bool ContainsElement(const std::vector
<T
>& collection
, const T
& key
) {
41 typename
std::vector
<T
>::const_iterator it
= collection
.begin();
42 while (it
!= collection
.end()) {
50 std::vector
<std::string
> GetVirtualPathComponents(
51 const storage::FileSystemURL
& url
) {
52 ImportedMediaGalleryRegistry
* imported_registry
=
53 ImportedMediaGalleryRegistry::GetInstance();
54 base::FilePath root
= imported_registry
->ImportedRoot().AppendASCII("iphoto");
56 DCHECK(root
.IsParent(url
.path()) || root
== url
.path());
57 base::FilePath virtual_path
;
58 root
.AppendRelativePath(url
.path(), &virtual_path
);
60 std::vector
<std::string
> result
;
61 storage::VirtualPath::GetComponentsUTF8Unsafe(virtual_path
, &result
);
67 const char kIPhotoAlbumsDir
[] = "Albums";
68 const char kIPhotoOriginalsDir
[] = "Originals";
70 IPhotoFileUtil::IPhotoFileUtil(MediaPathFilter
* media_path_filter
)
71 : NativeMediaFileUtil(media_path_filter
),
72 imported_registry_(NULL
),
76 IPhotoFileUtil::~IPhotoFileUtil() {
79 void IPhotoFileUtil::GetFileInfoOnTaskRunnerThread(
80 scoped_ptr
<storage::FileSystemOperationContext
> context
,
81 const storage::FileSystemURL
& url
,
82 const GetFileInfoCallback
& callback
) {
83 IPhotoDataProvider
* data_provider
= GetDataProvider();
84 // |data_provider| may be NULL if the file system was revoked before this
85 // operation had a chance to run.
87 GetFileInfoWithFreshDataProvider(context
.Pass(), url
, callback
, false);
89 data_provider
->RefreshData(
90 base::Bind(&IPhotoFileUtil::GetFileInfoWithFreshDataProvider
,
91 weak_factory_
.GetWeakPtr(), base::Passed(&context
), url
,
96 void IPhotoFileUtil::ReadDirectoryOnTaskRunnerThread(
97 scoped_ptr
<storage::FileSystemOperationContext
> context
,
98 const storage::FileSystemURL
& url
,
99 const ReadDirectoryCallback
& callback
) {
100 IPhotoDataProvider
* data_provider
= GetDataProvider();
101 // |data_provider| may be NULL if the file system was revoked before this
102 // operation had a chance to run.
103 if (!data_provider
) {
104 ReadDirectoryWithFreshDataProvider(context
.Pass(), url
, callback
, false);
106 data_provider
->RefreshData(
107 base::Bind(&IPhotoFileUtil::ReadDirectoryWithFreshDataProvider
,
108 weak_factory_
.GetWeakPtr(), base::Passed(&context
), url
,
113 void IPhotoFileUtil::CreateSnapshotFileOnTaskRunnerThread(
114 scoped_ptr
<storage::FileSystemOperationContext
> context
,
115 const storage::FileSystemURL
& url
,
116 const CreateSnapshotFileCallback
& callback
) {
117 IPhotoDataProvider
* data_provider
= GetDataProvider();
118 // |data_provider| may be NULL if the file system was revoked before this
119 // operation had a chance to run.
120 if (!data_provider
) {
121 CreateSnapshotFileWithFreshDataProvider(context
.Pass(), url
, callback
,
124 data_provider
->RefreshData(
125 base::Bind(&IPhotoFileUtil::CreateSnapshotFileWithFreshDataProvider
,
126 weak_factory_
.GetWeakPtr(), base::Passed(&context
), url
,
131 void IPhotoFileUtil::GetFileInfoWithFreshDataProvider(
132 scoped_ptr
<storage::FileSystemOperationContext
> context
,
133 const storage::FileSystemURL
& url
,
134 const GetFileInfoCallback
& callback
,
137 if (!callback
.is_null()) {
138 content::BrowserThread::PostTask(
139 content::BrowserThread::IO
,
141 base::Bind(callback
, base::File::FILE_ERROR_IO
, base::File::Info()));
145 NativeMediaFileUtil::GetFileInfoOnTaskRunnerThread(context
.Pass(), url
,
149 void IPhotoFileUtil::ReadDirectoryWithFreshDataProvider(
150 scoped_ptr
<storage::FileSystemOperationContext
> context
,
151 const storage::FileSystemURL
& url
,
152 const ReadDirectoryCallback
& callback
,
155 if (!callback
.is_null()) {
156 content::BrowserThread::PostTask(
157 content::BrowserThread::IO
,
159 base::Bind(callback
, base::File::FILE_ERROR_IO
, EntryList(), false));
163 NativeMediaFileUtil::ReadDirectoryOnTaskRunnerThread(context
.Pass(), url
,
167 void IPhotoFileUtil::CreateSnapshotFileWithFreshDataProvider(
168 scoped_ptr
<storage::FileSystemOperationContext
> context
,
169 const storage::FileSystemURL
& url
,
170 const CreateSnapshotFileCallback
& callback
,
173 if (!callback
.is_null()) {
174 base::File::Info file_info
;
175 base::FilePath platform_path
;
176 scoped_refptr
<storage::ShareableFileReference
> file_ref
;
177 content::BrowserThread::PostTask(
178 content::BrowserThread::IO
,
180 base::Bind(callback
, base::File::FILE_ERROR_IO
, file_info
,
181 platform_path
, file_ref
));
185 NativeMediaFileUtil::CreateSnapshotFileOnTaskRunnerThread(context
.Pass(), url
,
189 // Begin actual implementation.
191 base::File::Error
IPhotoFileUtil::GetFileInfoSync(
192 storage::FileSystemOperationContext
* context
,
193 const storage::FileSystemURL
& url
,
194 base::File::Info
* file_info
,
195 base::FilePath
* platform_path
) {
196 std::vector
<std::string
> components
= GetVirtualPathComponents(url
);
198 if (components
.size() == 0) {
199 return MakeDirectoryFileInfo(file_info
);
202 // The 'Albums' directory.
203 if (components
[0] == kIPhotoAlbumsDir
) {
204 if (components
.size() == 1) {
205 return MakeDirectoryFileInfo(file_info
);
206 } else if (components
.size() == 2) {
207 std::vector
<std::string
> albums
=
208 GetDataProvider()->GetAlbumNames();
209 if (ContainsElement(albums
, components
[1]))
210 return MakeDirectoryFileInfo(file_info
);
211 } else if (components
.size() == 3) {
212 if (components
[2] == kIPhotoOriginalsDir
) {
213 if (GetDataProvider()->HasOriginals(components
[1]))
214 return MakeDirectoryFileInfo(file_info
);
216 return base::File::FILE_ERROR_NOT_FOUND
;
219 base::FilePath location
= GetDataProvider()->GetPhotoLocationInAlbum(
220 components
[1], components
[2]);
221 if (!location
.empty()) {
222 return NativeMediaFileUtil::GetFileInfoSync(
223 context
, url
, file_info
, platform_path
);
225 } else if (components
.size() == 4 &&
226 GetDataProvider()->HasOriginals(components
[1]) &&
227 components
[2] == kIPhotoOriginalsDir
) {
228 base::FilePath location
= GetDataProvider()->GetOriginalPhotoLocation(
229 components
[1], components
[3]);
230 if (!location
.empty()) {
231 return NativeMediaFileUtil::GetFileInfoSync(
232 context
, url
, file_info
, platform_path
);
237 return base::File::FILE_ERROR_NOT_FOUND
;
240 base::File::Error
IPhotoFileUtil::ReadDirectorySync(
241 storage::FileSystemOperationContext
* context
,
242 const storage::FileSystemURL
& url
,
243 EntryList
* file_list
) {
244 DCHECK(file_list
->empty());
245 std::vector
<std::string
> components
= GetVirtualPathComponents(url
);
247 // Root directory. Child is the /Albums dir.
248 if (components
.size() == 0) {
249 file_list
->push_back(DirectoryEntry(kIPhotoAlbumsDir
,
250 DirectoryEntry::DIRECTORY
,
252 return base::File::FILE_OK
;
255 if (components
[0] == kIPhotoAlbumsDir
) {
256 if (components
.size() == 1) {
257 // Albums dir contains all album names.
258 std::vector
<std::string
> albums
=
259 GetDataProvider()->GetAlbumNames();
260 for (std::vector
<std::string
>::const_iterator it
= albums
.begin();
261 it
!= albums
.end(); it
++) {
262 file_list
->push_back(DirectoryEntry(*it
, DirectoryEntry::DIRECTORY
,
265 return base::File::FILE_OK
;
266 } else if (components
.size() == 2) {
267 std::vector
<std::string
> albums
=
268 GetDataProvider()->GetAlbumNames();
269 if (!ContainsElement(albums
, components
[1]))
270 return base::File::FILE_ERROR_NOT_FOUND
;
272 // Album dirs contain all photos in them.
273 if (GetDataProvider()->HasOriginals(components
[1])) {
274 file_list
->push_back(DirectoryEntry(kIPhotoOriginalsDir
,
275 DirectoryEntry::DIRECTORY
,
278 std::map
<std::string
, base::FilePath
> locations
=
279 GetDataProvider()->GetAlbumContents(components
[1]);
280 for (std::map
<std::string
, base::FilePath
>::const_iterator it
=
282 it
!= locations
.end(); it
++) {
283 base::File::Info info
;
284 if (!base::GetFileInfo(it
->second
, &info
))
285 return base::File::FILE_ERROR_IO
;
286 file_list
->push_back(DirectoryEntry(it
->first
, DirectoryEntry::FILE,
287 info
.size
, info
.last_modified
));
289 return base::File::FILE_OK
;
290 } else if (components
.size() == 3 &&
291 components
[2] == kIPhotoOriginalsDir
&&
292 GetDataProvider()->HasOriginals(components
[1])) {
293 std::map
<std::string
, base::FilePath
> originals
=
294 GetDataProvider()->GetOriginals(components
[1]);
295 for (std::map
<std::string
, base::FilePath
>::const_iterator it
=
297 it
!= originals
.end(); it
++) {
298 base::File::Info info
;
299 if (!base::GetFileInfo(it
->second
, &info
))
300 return base::File::FILE_ERROR_IO
;
301 file_list
->push_back(DirectoryEntry(it
->first
, DirectoryEntry::FILE,
302 info
.size
, info
.last_modified
));
304 return base::File::FILE_OK
;
308 return base::File::FILE_ERROR_NOT_FOUND
;
311 base::File::Error
IPhotoFileUtil::DeleteDirectorySync(
312 storage::FileSystemOperationContext
* context
,
313 const storage::FileSystemURL
& url
) {
314 return base::File::FILE_ERROR_SECURITY
;
317 base::File::Error
IPhotoFileUtil::DeleteFileSync(
318 storage::FileSystemOperationContext
* context
,
319 const storage::FileSystemURL
& url
) {
320 return base::File::FILE_ERROR_SECURITY
;
323 base::File::Error
IPhotoFileUtil::GetLocalFilePath(
324 storage::FileSystemOperationContext
* context
,
325 const storage::FileSystemURL
& url
,
326 base::FilePath
* local_file_path
) {
327 std::vector
<std::string
> components
= GetVirtualPathComponents(url
);
329 if (components
.size() == 3 && components
[0] == kIPhotoAlbumsDir
) {
330 base::FilePath location
= GetDataProvider()->GetPhotoLocationInAlbum(
331 components
[1], components
[2]);
332 if (!location
.empty()) {
333 *local_file_path
= location
;
334 return base::File::FILE_OK
;
338 if (components
.size() == 4 && components
[0] == kIPhotoAlbumsDir
&&
339 GetDataProvider()->HasOriginals(components
[1]) &&
340 components
[2] == kIPhotoOriginalsDir
) {
341 base::FilePath location
= GetDataProvider()->GetOriginalPhotoLocation(
342 components
[1], components
[3]);
343 if (!location
.empty()) {
344 *local_file_path
= location
;
345 return base::File::FILE_OK
;
349 return base::File::FILE_ERROR_NOT_FOUND
;
352 IPhotoDataProvider
* IPhotoFileUtil::GetDataProvider() {
353 if (!imported_registry_
)
354 imported_registry_
= ImportedMediaGalleryRegistry::GetInstance();
355 return imported_registry_
->IPhotoDataProvider();
358 } // namespace iphoto