summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/chrome_content_browser_client.cc13
-rw-r--r--chrome/browser/chrome_content_browser_client.h4
-rw-r--r--chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc353
-rw-r--r--chrome/browser/media_galleries/fileapi/device_media_async_file_util.h177
-rw-r--r--chrome/browser/media_galleries/fileapi/filtering_file_enumerator.cc107
-rw-r--r--chrome/browser/media_galleries/fileapi/filtering_file_enumerator.h41
-rw-r--r--chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.cc222
-rw-r--r--chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h95
-rw-r--r--chrome/browser/media_galleries/fileapi/media_path_filter.cc82
-rw-r--r--chrome/browser/media_galleries/fileapi/media_path_filter.h41
-rw-r--r--chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h85
-rw-r--r--chrome/browser/media_galleries/fileapi/mtp_device_file_system_config.h17
-rw-r--r--chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc73
-rw-r--r--chrome/browser/media_galleries/fileapi/mtp_device_map_service.h71
-rw-r--r--chrome/browser/media_galleries/fileapi/native_media_file_util.cc229
-rw-r--r--chrome/browser/media_galleries/fileapi/native_media_file_util.h85
-rw-r--r--chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc614
-rw-r--r--chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.cc186
-rw-r--r--chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h66
-rw-r--r--chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader_unittest.cc179
-rw-r--r--chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h46
-rw-r--r--chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.cc88
-rw-r--r--chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h47
-rw-r--r--chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader_unittest.cc72
-rw-r--r--chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.cc172
-rw-r--r--chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h55
-rw-r--r--chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h4
-rw-r--r--chrome/browser/media_galleries/linux/mtp_device_task_helper.h6
-rw-r--r--chrome/browser/media_galleries/linux/snapshot_file_details.cc4
-rw-r--r--chrome/browser/media_galleries/linux/snapshot_file_details.h14
-rw-r--r--chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h4
-rw-r--r--chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm1
-rw-r--r--chrome/browser/media_galleries/media_file_system_context.h2
-rw-r--r--chrome/browser/media_galleries/media_file_system_registry.h2
-rw-r--r--chrome/browser/media_galleries/mtp_device_delegate_impl.h6
-rw-r--r--chrome/browser/media_galleries/scoped_mtp_device_map_entry.cc11
-rw-r--r--chrome/browser/media_galleries/scoped_mtp_device_map_entry.h9
-rw-r--r--chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h4
-rw-r--r--chrome/browser/media_galleries/win/snapshot_file_details.cc2
-rw-r--r--chrome/browser/media_galleries/win/snapshot_file_details.h10
40 files changed, 3257 insertions, 42 deletions
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 39d0c49..af5a007 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -170,6 +170,10 @@
#include "chrome/browser/signin/signin_manager_factory.h"
#endif
+#if !defined(OS_ANDROID)
+#include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h"
+#endif
+
using base::FileDescriptor;
using content::AccessTokenStore;
using content::BrowserChildProcessHostIterator;
@@ -2108,6 +2112,15 @@ void ChromeContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
additional_allowed_schemes->push_back(extensions::kExtensionScheme);
}
+void ChromeContentBrowserClient::GetAdditionalFileSystemMountPointProviders(
+ const base::FilePath& storage_partition_path,
+ ScopedVector<fileapi::FileSystemMountPointProvider>* additional_providers) {
+#if !defined(OS_ANDROID)
+ additional_providers->push_back(new MediaFileSystemMountPointProvider(
+ storage_partition_path));
+#endif
+}
+
#if defined(OS_POSIX) && !defined(OS_MACOSX)
void ChromeContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
const CommandLine& command_line,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 9b899a6..4a5f5c6 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -224,6 +224,10 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
content::WebContents* web_contents) OVERRIDE;
virtual void GetAdditionalAllowedSchemesForFileSystem(
std::vector<std::string>* additional_schemes) OVERRIDE;
+ virtual void GetAdditionalFileSystemMountPointProviders(
+ const base::FilePath& storage_partition_path,
+ ScopedVector<fileapi::FileSystemMountPointProvider>*
+ additional_providers) OVERRIDE;
#if defined(OS_POSIX) && !defined(OS_MACOSX)
virtual void GetAdditionalMappedFilesForChildProcess(
diff --git a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
new file mode 100644
index 0000000..1c7046c
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
@@ -0,0 +1,353 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media_galleries/fileapi/device_media_async_file_util.h"
+
+#include "base/callback.h"
+#include "base/file_util.h"
+#include "base/single_thread_task_runner.h"
+#include "chrome/browser/media_galleries/fileapi/filtering_file_enumerator.h"
+#include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h"
+#include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h"
+#include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_operation_context.h"
+#include "webkit/fileapi/file_system_task_runners.h"
+#include "webkit/fileapi/file_system_url.h"
+#include "webkit/fileapi/isolated_context.h"
+
+using fileapi::FileSystemOperationContext;
+using fileapi::FileSystemURL;
+
+namespace chrome {
+
+namespace {
+
+const base::FilePath::CharType kDeviceMediaAsyncFileUtilTempDir[] =
+ FILE_PATH_LITERAL("DeviceMediaFileSystem");
+
+// Returns true if the current thread is IO thread.
+bool IsOnIOThread(FileSystemOperationContext* context) {
+ return context->file_system_context()->task_runners()->
+ io_task_runner()->RunsTasksOnCurrentThread();
+}
+
+// Called on the IO thread.
+MTPDeviceAsyncDelegate* GetMTPDeviceDelegate(
+ FileSystemOperationContext* context) {
+ DCHECK(IsOnIOThread(context));
+ return MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(
+ context->GetUserValue<std::string>(
+ MediaFileSystemMountPointProvider::kMTPDeviceDelegateURLKey));
+}
+
+// Called on a blocking pool thread to create a snapshot file to hold the
+// contents of |device_file_path|. The snapshot file is created in
+// "profile_path/kDeviceMediaAsyncFileUtilTempDir" directory. If the snapshot
+// file is created successfully, |snapshot_file_path| will be a non-empty file
+// path. In case of failure, the |snapshot_file_path| will be an empty file
+// path.
+void CreateSnapshotFileOnBlockingPool(
+ const base::FilePath& device_file_path,
+ const base::FilePath& profile_path,
+ base::FilePath* snapshot_file_path) {
+ DCHECK(snapshot_file_path);
+ base::FilePath isolated_media_file_system_dir_path =
+ profile_path.Append(kDeviceMediaAsyncFileUtilTempDir);
+ if (!file_util::CreateDirectory(isolated_media_file_system_dir_path) ||
+ !file_util::CreateTemporaryFileInDir(isolated_media_file_system_dir_path,
+ snapshot_file_path)) {
+ LOG(WARNING) << "Could not create media snapshot file "
+ << isolated_media_file_system_dir_path.value();
+ *snapshot_file_path = base::FilePath();
+ }
+}
+
+} // namespace
+
+DeviceMediaAsyncFileUtil::~DeviceMediaAsyncFileUtil() {
+}
+
+// static
+DeviceMediaAsyncFileUtil* DeviceMediaAsyncFileUtil::Create(
+ const base::FilePath& profile_path) {
+ DCHECK(!profile_path.empty());
+ return new DeviceMediaAsyncFileUtil(profile_path);
+}
+
+bool DeviceMediaAsyncFileUtil::CreateOrOpen(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ int file_flags,
+ const CreateOrOpenCallback& callback) {
+ DCHECK(IsOnIOThread(context));
+ NOTIMPLEMENTED();
+ if (!callback.is_null()) {
+ base::PlatformFile invalid_file = base::kInvalidPlatformFileValue;
+ callback.Run(base::PLATFORM_FILE_ERROR_SECURITY,
+ base::PassPlatformFile(&invalid_file),
+ false);
+ }
+ return true;
+}
+
+bool DeviceMediaAsyncFileUtil::EnsureFileExists(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const EnsureFileExistsCallback& callback) {
+ DCHECK(IsOnIOThread(context));
+ NOTIMPLEMENTED();
+ if (!callback.is_null())
+ callback.Run(base::PLATFORM_FILE_ERROR_SECURITY, false);
+ return true;
+}
+
+bool DeviceMediaAsyncFileUtil::CreateDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ bool exclusive,
+ bool recursive,
+ const StatusCallback& callback) {
+ DCHECK(IsOnIOThread(context));
+ NOTIMPLEMENTED();
+ if (!callback.is_null())
+ callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
+ return true;
+}
+
+bool DeviceMediaAsyncFileUtil::GetFileInfo(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const GetFileInfoCallback& callback) {
+ DCHECK(IsOnIOThread(context));
+ MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(context);
+ if (!delegate) {
+ OnGetFileInfoError(callback, url.path(),
+ base::PLATFORM_FILE_ERROR_NOT_FOUND);
+ return true;
+ }
+ delegate->GetFileInfo(
+ url.path(),
+ base::Bind(&DeviceMediaAsyncFileUtil::OnDidGetFileInfo,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ url.path()),
+ base::Bind(&DeviceMediaAsyncFileUtil::OnGetFileInfoError,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ url.path()));
+ return true;
+}
+
+bool DeviceMediaAsyncFileUtil::ReadDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const ReadDirectoryCallback& callback) {
+ DCHECK(IsOnIOThread(context));
+ MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(context);
+ if (!delegate) {
+ OnReadDirectoryError(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND);
+ return true;
+ }
+ delegate->ReadDirectory(
+ url.path(),
+ base::Bind(&DeviceMediaAsyncFileUtil::OnDidReadDirectory,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback),
+ base::Bind(&DeviceMediaAsyncFileUtil::OnReadDirectoryError,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+ return true;
+}
+
+bool DeviceMediaAsyncFileUtil::Touch(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ const StatusCallback& callback) {
+ DCHECK(IsOnIOThread(context));
+ NOTIMPLEMENTED();
+ if (!callback.is_null())
+ callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
+ return true;
+}
+
+bool DeviceMediaAsyncFileUtil::Truncate(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ int64 length,
+ const StatusCallback& callback) {
+ DCHECK(IsOnIOThread(context));
+ NOTIMPLEMENTED();
+ if (!callback.is_null())
+ callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
+ return true;
+}
+
+bool DeviceMediaAsyncFileUtil::CopyFileLocal(
+ FileSystemOperationContext* context,
+ const FileSystemURL& src_url,
+ const FileSystemURL& dest_url,
+ const StatusCallback& callback) {
+ DCHECK(IsOnIOThread(context));
+ NOTIMPLEMENTED();
+ if (!callback.is_null())
+ callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
+ return true;
+}
+
+bool DeviceMediaAsyncFileUtil::MoveFileLocal(
+ FileSystemOperationContext* context,
+ const FileSystemURL& src_url,
+ const FileSystemURL& dest_url,
+ const StatusCallback& callback) {
+ DCHECK(IsOnIOThread(context));
+ NOTIMPLEMENTED();
+ if (!callback.is_null())
+ callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
+ return true;
+}
+
+bool DeviceMediaAsyncFileUtil::CopyInForeignFile(
+ FileSystemOperationContext* context,
+ const base::FilePath& src_file_path,
+ const FileSystemURL& dest_url,
+ const StatusCallback& callback) {
+ DCHECK(IsOnIOThread(context));
+ NOTIMPLEMENTED();
+ if (!callback.is_null())
+ callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
+ return true;
+}
+
+bool DeviceMediaAsyncFileUtil::DeleteFile(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const StatusCallback& callback) {
+ DCHECK(IsOnIOThread(context));
+ NOTIMPLEMENTED();
+ if (!callback.is_null())
+ callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
+ return true;
+}
+
+bool DeviceMediaAsyncFileUtil::DeleteDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const StatusCallback& callback) {
+ DCHECK(IsOnIOThread(context));
+ NOTIMPLEMENTED();
+ if (!callback.is_null())
+ callback.Run(base::PLATFORM_FILE_ERROR_SECURITY);
+ return true;
+}
+
+bool DeviceMediaAsyncFileUtil::CreateSnapshotFile(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const CreateSnapshotFileCallback& callback) {
+ DCHECK(IsOnIOThread(context));
+ MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(context);
+ if (!delegate) {
+ OnCreateSnapshotFileError(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND);
+ return true;
+ }
+ base::FilePath* snapshot_file_path = new base::FilePath;
+ return context->task_runner()->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&CreateSnapshotFileOnBlockingPool,
+ url.path(),
+ profile_path_,
+ base::Unretained(snapshot_file_path)),
+ base::Bind(&DeviceMediaAsyncFileUtil::OnSnapshotFileCreatedRunTask,
+ weak_ptr_factory_.GetWeakPtr(),
+ context,
+ callback,
+ url.path(),
+ base::Owned(snapshot_file_path)));
+}
+
+DeviceMediaAsyncFileUtil::DeviceMediaAsyncFileUtil(
+ const base::FilePath& profile_path)
+ : profile_path_(profile_path),
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
+}
+
+void DeviceMediaAsyncFileUtil::OnDidGetFileInfo(
+ const AsyncFileUtil::GetFileInfoCallback& callback,
+ const base::FilePath& platform_path,
+ const base::PlatformFileInfo& file_info) {
+ if (!callback.is_null())
+ callback.Run(base::PLATFORM_FILE_OK, file_info, platform_path);
+}
+
+void DeviceMediaAsyncFileUtil::OnGetFileInfoError(
+ const AsyncFileUtil::GetFileInfoCallback& callback,
+ const base::FilePath& platform_path,
+ base::PlatformFileError error) {
+ if (!callback.is_null())
+ callback.Run(error, base::PlatformFileInfo(), platform_path);
+}
+
+void DeviceMediaAsyncFileUtil::OnDidReadDirectory(
+ const AsyncFileUtil::ReadDirectoryCallback& callback,
+ const AsyncFileUtil::EntryList& file_list,
+ bool has_more) {
+ if (!callback.is_null())
+ callback.Run(base::PLATFORM_FILE_OK, file_list, has_more);
+}
+
+void DeviceMediaAsyncFileUtil::OnReadDirectoryError(
+ const AsyncFileUtil::ReadDirectoryCallback& callback,
+ base::PlatformFileError error) {
+ if (!callback.is_null())
+ callback.Run(error, AsyncFileUtil::EntryList(), false /*no more*/);
+}
+
+void DeviceMediaAsyncFileUtil::OnDidCreateSnapshotFile(
+ const AsyncFileUtil::CreateSnapshotFileCallback& callback,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& platform_path) {
+ if (!callback.is_null())
+ callback.Run(base::PLATFORM_FILE_OK, file_info, platform_path,
+ fileapi::kSnapshotFileTemporary);
+}
+
+void DeviceMediaAsyncFileUtil::OnCreateSnapshotFileError(
+ const AsyncFileUtil::CreateSnapshotFileCallback& callback,
+ base::PlatformFileError error) {
+ if (!callback.is_null())
+ callback.Run(error, base::PlatformFileInfo(), base::FilePath(),
+ fileapi::kSnapshotFileTemporary);
+}
+
+void DeviceMediaAsyncFileUtil::OnSnapshotFileCreatedRunTask(
+ FileSystemOperationContext* context,
+ const AsyncFileUtil::CreateSnapshotFileCallback& callback,
+ const base::FilePath& device_file_path,
+ base::FilePath* snapshot_file_path) {
+ DCHECK(IsOnIOThread(context));
+ if (!snapshot_file_path || snapshot_file_path->empty()) {
+ OnCreateSnapshotFileError(callback, base::PLATFORM_FILE_ERROR_FAILED);
+ return;
+ }
+ MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(context);
+ if (!delegate) {
+ OnCreateSnapshotFileError(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND);
+ return;
+ }
+ delegate->CreateSnapshotFile(
+ device_file_path,
+ *snapshot_file_path,
+ base::Bind(&DeviceMediaAsyncFileUtil::OnDidCreateSnapshotFile,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback),
+ base::Bind(&DeviceMediaAsyncFileUtil::OnCreateSnapshotFileError,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
+}
+
+} // namespace chrome
diff --git a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h
new file mode 100644
index 0000000..dde43a8
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_DEVICE_MEDIA_ASYNC_FILE_UTIL_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_DEVICE_MEDIA_ASYNC_FILE_UTIL_H_
+
+#include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
+#include "base/platform_file.h"
+#include "webkit/fileapi/async_file_util.h"
+
+namespace base {
+class Time;
+}
+
+namespace fileapi {
+class FileSystemOperationContext;
+class FileSystemURL;
+}
+
+namespace chrome {
+
+class DeviceMediaAsyncFileUtil : public fileapi::AsyncFileUtil {
+ public:
+ virtual ~DeviceMediaAsyncFileUtil();
+
+ // Returns an instance of DeviceMediaAsyncFileUtil. Returns NULL if
+ // asynchronous operation is not supported. Callers own the returned
+ // object.
+ static DeviceMediaAsyncFileUtil* Create(const base::FilePath& profile_path);
+
+ // AsyncFileUtil overrides.
+ virtual bool CreateOrOpen(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ int file_flags,
+ const CreateOrOpenCallback& callback) OVERRIDE;
+ virtual bool EnsureFileExists(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ const EnsureFileExistsCallback& callback) OVERRIDE;
+ virtual bool CreateDirectory(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ bool exclusive,
+ bool recursive,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool GetFileInfo(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ const GetFileInfoCallback& callback) OVERRIDE;
+ virtual bool ReadDirectory(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ const ReadDirectoryCallback& callback) OVERRIDE;
+ virtual bool Touch(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool Truncate(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ int64 length,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool CopyFileLocal(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& src_url,
+ const fileapi::FileSystemURL& dest_url,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool MoveFileLocal(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& src_url,
+ const fileapi::FileSystemURL& dest_url,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool CopyInForeignFile(
+ fileapi::FileSystemOperationContext* context,
+ const base::FilePath& src_file_path,
+ const fileapi::FileSystemURL& dest_url,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool DeleteFile(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool DeleteDirectory(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ const StatusCallback& callback) OVERRIDE;
+ virtual bool CreateSnapshotFile(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ const CreateSnapshotFileCallback& callback) OVERRIDE;
+
+ private:
+ // Use Create() to get an instance of DeviceMediaAsyncFileUtil.
+ explicit DeviceMediaAsyncFileUtil(const base::FilePath& profile_path);
+
+ // Called when GetFileInfo method call succeeds. |file_info|
+ // contains the |platform_path| file details. |callback| is invoked
+ // to complete the GetFileInfo request.
+ void OnDidGetFileInfo(
+ const AsyncFileUtil::GetFileInfoCallback& callback,
+ const base::FilePath& platform_path,
+ const base::PlatformFileInfo& file_info);
+
+ // Called when GetFileInfo method call failed to get the details of file
+ // specified by the |platform_path|. |callback| is invoked to notify the
+ // caller about the platform file |error|.
+ void OnGetFileInfoError(
+ const AsyncFileUtil::GetFileInfoCallback& callback,
+ const base::FilePath& platform_path,
+ base::PlatformFileError error);
+
+ // Called when ReadDirectory method call succeeds. |callback| is invoked to
+ // complete the ReadDirectory request.
+ //
+ // If the contents of the given directory are reported in one batch, then
+ // |file_list| will have the list of all files/directories in the given
+ // directory and |has_more| will be false.
+ //
+ // If the contents of the given directory are reported in multiple chunks,
+ // |file_list| will have only a subset of all contents (the subsets reported
+ // in any two calls are disjoint), and |has_more| will be true, except for
+ // the last chunk.
+ void OnDidReadDirectory(
+ const AsyncFileUtil::ReadDirectoryCallback& callback,
+ const AsyncFileUtil::EntryList& file_list,
+ bool has_more);
+
+ // Called when ReadDirectory method call failed to enumerate the directory
+ // objects. |callback| is invoked to notify the caller about the |error|
+ // that occured while reading the directory objects.
+ void OnReadDirectoryError(
+ const AsyncFileUtil::ReadDirectoryCallback& callback,
+ base::PlatformFileError error);
+
+ // Called when the snapshot file specified by the |platform_path| is
+ // successfully created. |file_info| contains the device media file details
+ // for which the snapshot file is created. |callback| is invoked to complete
+ // the CreateSnapshotFile request.
+ void OnDidCreateSnapshotFile(
+ const AsyncFileUtil::CreateSnapshotFileCallback& callback,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& platform_path);
+
+ // Called when CreateSnapshotFile method call fails. |callback| is invoked to
+ // notify the caller about the |error|.
+ void OnCreateSnapshotFileError(
+ const AsyncFileUtil::CreateSnapshotFileCallback& callback,
+ base::PlatformFileError error);
+
+ // Called when the snapshot file specified by the |snapshot_file_path| is
+ // created to hold the contents of the |device_file_path|. If the snapshot
+ // file is successfully created, |snapshot_file_path| will be an non-empty
+ // file path. In case of failure, |snapshot_file_path| will be an empty file
+ // path. Forwards the CreateSnapshot request to the delegate to copy the
+ // contents of |device_file_path| to |snapshot_file_path|.
+ void OnSnapshotFileCreatedRunTask(
+ fileapi::FileSystemOperationContext* context,
+ const AsyncFileUtil::CreateSnapshotFileCallback& callback,
+ const base::FilePath& device_file_path,
+ base::FilePath* snapshot_file_path);
+
+ // Profile path.
+ const base::FilePath profile_path_;
+
+ // For callbacks that may run after destruction.
+ base::WeakPtrFactory<DeviceMediaAsyncFileUtil> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceMediaAsyncFileUtil);
+};
+
+} // namespace chrome
+
+#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_DEVICE_MEDIA_ASYNC_FILE_UTIL_H_
diff --git a/chrome/browser/media_galleries/fileapi/filtering_file_enumerator.cc b/chrome/browser/media_galleries/fileapi/filtering_file_enumerator.cc
new file mode 100644
index 0000000..cbb52b3
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/filtering_file_enumerator.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media_galleries/fileapi/filtering_file_enumerator.h"
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#else
+#include <cstring>
+
+#include "base/string_util.h"
+#endif
+
+namespace chrome {
+
+namespace {
+
+// Used to skip the hidden folders and files. Returns true if the file specified
+// by |path| should be skipped.
+bool ShouldSkip(const base::FilePath& path) {
+ const base::FilePath& base_name = path.BaseName();
+ if (base_name.empty())
+ return false;
+
+ // Dot files (aka hidden files)
+ if (base_name.value()[0] == '.')
+ return true;
+
+ // Mac OS X file.
+ if (base_name.value() == FILE_PATH_LITERAL("__MACOSX"))
+ return true;
+
+#if defined(OS_WIN)
+ DWORD file_attributes = ::GetFileAttributes(path.value().c_str());
+ if ((file_attributes != INVALID_FILE_ATTRIBUTES) &&
+ ((file_attributes & FILE_ATTRIBUTE_HIDDEN) != 0))
+ return true;
+#else
+ // Windows always creates a recycle bin folder in the attached device to store
+ // all the deleted contents. On non-windows operating systems, there is no way
+ // to get the hidden attribute of windows recycle bin folders that are present
+ // on the attached device. Therefore, compare the file path name to the
+ // recycle bin name and exclude those folders. For more details, please refer
+ // to http://support.microsoft.com/kb/171694.
+ const char win_98_recycle_bin_name[] = "RECYCLED";
+ const char win_xp_recycle_bin_name[] = "RECYCLER";
+ const char win_vista_recycle_bin_name[] = "$Recycle.bin";
+ if ((base::strncasecmp(base_name.value().c_str(),
+ win_98_recycle_bin_name,
+ strlen(win_98_recycle_bin_name)) == 0) ||
+ (base::strncasecmp(base_name.value().c_str(),
+ win_xp_recycle_bin_name,
+ strlen(win_xp_recycle_bin_name)) == 0) ||
+ (base::strncasecmp(base_name.value().c_str(),
+ win_vista_recycle_bin_name,
+ strlen(win_vista_recycle_bin_name)) == 0))
+ return true;
+#endif
+ return false;
+}
+
+} // namespace
+
+FilteringFileEnumerator::FilteringFileEnumerator(
+ scoped_ptr<fileapi::FileSystemFileUtil::AbstractFileEnumerator>
+ base_enumerator,
+ MediaPathFilter* filter)
+ : base_enumerator_(base_enumerator.Pass()),
+ filter_(filter) {
+ DCHECK(base_enumerator_.get());
+ DCHECK(filter);
+}
+
+FilteringFileEnumerator::~FilteringFileEnumerator() {
+}
+
+base::FilePath FilteringFileEnumerator::Next() {
+ while (true) {
+ base::FilePath next = base_enumerator_->Next();
+ if (ShouldSkip(next))
+ continue;
+
+ if (next.empty() ||
+ base_enumerator_->IsDirectory() ||
+ filter_->Match(next))
+ return next;
+ }
+}
+
+int64 FilteringFileEnumerator::Size() {
+ return base_enumerator_->Size();
+}
+
+base::Time FilteringFileEnumerator::LastModifiedTime() {
+ return base_enumerator_->LastModifiedTime();
+}
+
+bool FilteringFileEnumerator::IsDirectory() {
+ return base_enumerator_->IsDirectory();
+}
+
+} // namespace chrome
diff --git a/chrome/browser/media_galleries/fileapi/filtering_file_enumerator.h b/chrome/browser/media_galleries/fileapi/filtering_file_enumerator.h
new file mode 100644
index 0000000..7e17dae
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/filtering_file_enumerator.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_FILTERING_FILE_ENUMERATOR_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_FILTERING_FILE_ENUMERATOR_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
+#include "webkit/fileapi/file_system_file_util.h"
+
+namespace chrome {
+
+// This class wraps another file enumerator and filters out non-media files
+// from its result, refering given MediaPathFilter.
+class FilteringFileEnumerator
+ : public fileapi::FileSystemFileUtil::AbstractFileEnumerator {
+ public:
+ FilteringFileEnumerator(
+ scoped_ptr<fileapi::FileSystemFileUtil::AbstractFileEnumerator>
+ base_enumerator,
+ MediaPathFilter* filter);
+ virtual ~FilteringFileEnumerator();
+
+ virtual base::FilePath Next() OVERRIDE;
+ virtual int64 Size() OVERRIDE;
+ virtual base::Time LastModifiedTime() OVERRIDE;
+ virtual bool IsDirectory() OVERRIDE;
+
+ private:
+ // The file enumerator to be wrapped.
+ scoped_ptr<fileapi::FileSystemFileUtil::AbstractFileEnumerator>
+ base_enumerator_;
+
+ // Path filter to filter out non-Media files.
+ MediaPathFilter* filter_;
+};
+
+} // namespace chrome
+
+#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_FILTERING_FILE_ENUMERATOR_H_
diff --git a/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.cc b/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.cc
new file mode 100644
index 0000000..6fb69c6
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.cc
@@ -0,0 +1,222 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/message_loop_proxy.h"
+#include "base/platform_file.h"
+#include "base/sequenced_task_runner.h"
+#include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
+#include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
+#include "webkit/blob/local_file_stream_reader.h"
+#include "webkit/fileapi/async_file_util_adapter.h"
+#include "webkit/fileapi/copy_or_move_file_validator.h"
+#include "webkit/fileapi/file_system_callback_dispatcher.h"
+#include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_file_stream_reader.h"
+#include "webkit/fileapi/file_system_operation_context.h"
+#include "webkit/fileapi/file_system_task_runners.h"
+#include "webkit/fileapi/file_system_types.h"
+#include "webkit/fileapi/file_system_util.h"
+#include "webkit/fileapi/isolated_context.h"
+#include "webkit/fileapi/isolated_file_util.h"
+#include "webkit/fileapi/local_file_stream_writer.h"
+#include "webkit/fileapi/local_file_system_operation.h"
+#include "webkit/fileapi/native_file_util.h"
+
+#if defined(SUPPORT_MTP_DEVICE_FILESYSTEM)
+#include "chrome/browser/media_galleries/fileapi/device_media_async_file_util.h"
+#endif
+
+using fileapi::FileSystemContext;
+using fileapi::FileSystemType;
+using fileapi::FileSystemURL;
+
+namespace chrome {
+
+const char MediaFileSystemMountPointProvider::kMediaPathFilterKey[] =
+ "MediaPathFilterKey";
+const char MediaFileSystemMountPointProvider::kMTPDeviceDelegateURLKey[] =
+ "MTPDeviceDelegateKey";
+
+MediaFileSystemMountPointProvider::MediaFileSystemMountPointProvider(
+ const base::FilePath& profile_path)
+ : profile_path_(profile_path),
+ media_path_filter_(new MediaPathFilter()),
+ native_media_file_util_(
+ new fileapi::AsyncFileUtilAdapter(new NativeMediaFileUtil())) {
+#if defined(SUPPORT_MTP_DEVICE_FILESYSTEM)
+ // TODO(kmadhusu): Initialize |device_media_file_util_| in
+ // initialization list.
+ device_media_async_file_util_.reset(
+ DeviceMediaAsyncFileUtil::Create(profile_path_));
+#endif
+}
+
+MediaFileSystemMountPointProvider::~MediaFileSystemMountPointProvider() {
+}
+
+bool MediaFileSystemMountPointProvider::CanHandleType(
+ FileSystemType type) const {
+ switch (type) {
+ case fileapi::kFileSystemTypeNativeMedia:
+ case fileapi::kFileSystemTypeDeviceMedia:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void MediaFileSystemMountPointProvider::ValidateFileSystemRoot(
+ const GURL& origin_url,
+ FileSystemType type,
+ bool create,
+ const ValidateFileSystemCallback& callback) {
+ // We never allow opening a new isolated FileSystem via usual OpenFileSystem.
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(callback, base::PLATFORM_FILE_ERROR_SECURITY));
+}
+
+base::FilePath
+MediaFileSystemMountPointProvider::GetFileSystemRootPathOnFileThread(
+ const FileSystemURL& url,
+ bool create) {
+ // This is not supposed to be used.
+ NOTREACHED();
+ return base::FilePath();
+}
+
+fileapi::FileSystemFileUtil* MediaFileSystemMountPointProvider::GetFileUtil(
+ FileSystemType type) {
+ switch (type) {
+ case fileapi::kFileSystemTypeNativeMedia:
+ return native_media_file_util_->sync_file_util();
+ default:
+ NOTREACHED();
+ }
+ return NULL;
+}
+
+fileapi::AsyncFileUtil* MediaFileSystemMountPointProvider::GetAsyncFileUtil(
+ FileSystemType type) {
+ switch (type) {
+ case fileapi::kFileSystemTypeNativeMedia:
+ return native_media_file_util_.get();
+ case fileapi::kFileSystemTypeDeviceMedia:
+#if defined(SUPPORT_MTP_DEVICE_FILESYSTEM)
+ return device_media_async_file_util_.get();
+#endif
+ default:
+ NOTREACHED();
+ }
+ return NULL;
+}
+
+fileapi::CopyOrMoveFileValidatorFactory*
+MediaFileSystemMountPointProvider::GetCopyOrMoveFileValidatorFactory(
+ FileSystemType type, base::PlatformFileError* error_code) {
+ DCHECK(error_code);
+ *error_code = base::PLATFORM_FILE_OK;
+ switch (type) {
+ case fileapi::kFileSystemTypeNativeMedia:
+ case fileapi::kFileSystemTypeDeviceMedia:
+ if (!media_copy_or_move_file_validator_factory_) {
+ *error_code = base::PLATFORM_FILE_ERROR_SECURITY;
+ return NULL;
+ }
+ return media_copy_or_move_file_validator_factory_.get();
+ default:
+ NOTREACHED();
+ }
+ return NULL;
+}
+
+void
+MediaFileSystemMountPointProvider::InitializeCopyOrMoveFileValidatorFactory(
+ FileSystemType type,
+ scoped_ptr<fileapi::CopyOrMoveFileValidatorFactory> factory) {
+ switch (type) {
+ case fileapi::kFileSystemTypeNativeMedia:
+ case fileapi::kFileSystemTypeDeviceMedia:
+ if (!media_copy_or_move_file_validator_factory_)
+ media_copy_or_move_file_validator_factory_.reset(factory.release());
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+fileapi::FilePermissionPolicy
+MediaFileSystemMountPointProvider::GetPermissionPolicy(
+ const FileSystemURL& url, int permissions) const {
+ // Access to media file systems should be checked using per-filesystem
+ // access permission.
+ return fileapi::FILE_PERMISSION_USE_FILESYSTEM_PERMISSION;
+}
+
+fileapi::FileSystemOperation*
+MediaFileSystemMountPointProvider::CreateFileSystemOperation(
+ const FileSystemURL& url,
+ FileSystemContext* context,
+ base::PlatformFileError* error_code) const {
+ scoped_ptr<fileapi::FileSystemOperationContext> operation_context(
+ new fileapi::FileSystemOperationContext(
+ context, context->task_runners()->media_task_runner()));
+
+ operation_context->SetUserValue(kMediaPathFilterKey,
+ media_path_filter_.get());
+#if defined(SUPPORT_MTP_DEVICE_FILESYSTEM)
+ if (url.type() == fileapi::kFileSystemTypeDeviceMedia) {
+ operation_context->SetUserValue(kMTPDeviceDelegateURLKey,
+ url.filesystem_id());
+ }
+#endif
+
+ return new fileapi::LocalFileSystemOperation(context,
+ operation_context.Pass());
+}
+
+scoped_ptr<webkit_blob::FileStreamReader>
+MediaFileSystemMountPointProvider::CreateFileStreamReader(
+ const FileSystemURL& url,
+ int64 offset,
+ const base::Time& expected_modification_time,
+ FileSystemContext* context) const {
+ return scoped_ptr<webkit_blob::FileStreamReader>(
+ new webkit_blob::LocalFileStreamReader(
+ context->task_runners()->file_task_runner(),
+ url.path(), offset, expected_modification_time));
+}
+
+scoped_ptr<fileapi::FileStreamWriter>
+MediaFileSystemMountPointProvider::CreateFileStreamWriter(
+ const FileSystemURL& url,
+ int64 offset,
+ FileSystemContext* context) const {
+ return scoped_ptr<fileapi::FileStreamWriter>(
+ new fileapi::LocalFileStreamWriter(url.path(), offset));
+}
+
+fileapi::FileSystemQuotaUtil*
+MediaFileSystemMountPointProvider::GetQuotaUtil() {
+ // No quota support.
+ return NULL;
+}
+
+void MediaFileSystemMountPointProvider::DeleteFileSystem(
+ const GURL& origin_url,
+ FileSystemType type,
+ FileSystemContext* context,
+ const DeleteFileSystemCallback& callback) {
+ NOTREACHED();
+ callback.Run(base::PLATFORM_FILE_ERROR_INVALID_OPERATION);
+}
+
+} // namespace chrome
diff --git a/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h b/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h
new file mode 100644
index 0000000..27c6004
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MEDIA_FILE_SYSTEM_MOUNT_POINT_PROVIDER_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MEDIA_FILE_SYSTEM_MOUNT_POINT_PROVIDER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_file_system_config.h"
+#include "webkit/fileapi/file_system_mount_point_provider.h"
+
+namespace fileapi {
+class AsyncFileUtilAdapter;
+}
+
+namespace chrome {
+
+class MediaPathFilter;
+
+#if defined(SUPPORT_MTP_DEVICE_FILESYSTEM)
+class DeviceMediaAsyncFileUtil;
+#endif
+
+class MediaFileSystemMountPointProvider
+ : public fileapi::FileSystemMountPointProvider {
+ public:
+ static const char kMediaPathFilterKey[];
+ static const char kMTPDeviceDelegateURLKey[];
+
+ explicit MediaFileSystemMountPointProvider(
+ const base::FilePath& profile_path);
+ virtual ~MediaFileSystemMountPointProvider();
+
+ // FileSystemMountPointProvider implementation.
+ virtual bool CanHandleType(fileapi::FileSystemType type) const OVERRIDE;
+ virtual void ValidateFileSystemRoot(
+ const GURL& origin_url,
+ fileapi::FileSystemType type,
+ bool create,
+ const ValidateFileSystemCallback& callback) OVERRIDE;
+ virtual base::FilePath GetFileSystemRootPathOnFileThread(
+ const fileapi::FileSystemURL& url,
+ bool create) OVERRIDE;
+ virtual fileapi::FileSystemFileUtil* GetFileUtil(
+ fileapi::FileSystemType type) OVERRIDE;
+ virtual fileapi::AsyncFileUtil* GetAsyncFileUtil(
+ fileapi::FileSystemType type) OVERRIDE;
+ virtual fileapi::CopyOrMoveFileValidatorFactory*
+ GetCopyOrMoveFileValidatorFactory(
+ fileapi::FileSystemType type,
+ base::PlatformFileError* error_code) OVERRIDE;
+ virtual void InitializeCopyOrMoveFileValidatorFactory(
+ fileapi::FileSystemType type,
+ scoped_ptr<fileapi::CopyOrMoveFileValidatorFactory> factory) OVERRIDE;
+ virtual fileapi::FilePermissionPolicy GetPermissionPolicy(
+ const fileapi::FileSystemURL& url, int permissions) const OVERRIDE;
+ virtual fileapi::FileSystemOperation* CreateFileSystemOperation(
+ const fileapi::FileSystemURL& url,
+ fileapi::FileSystemContext* context,
+ base::PlatformFileError* error_code) const OVERRIDE;
+ virtual scoped_ptr<webkit_blob::FileStreamReader> CreateFileStreamReader(
+ const fileapi::FileSystemURL& url,
+ int64 offset,
+ const base::Time& expected_modification_time,
+ fileapi::FileSystemContext* context) const OVERRIDE;
+ virtual scoped_ptr<fileapi::FileStreamWriter> CreateFileStreamWriter(
+ const fileapi::FileSystemURL& url,
+ int64 offset,
+ fileapi::FileSystemContext* context) const OVERRIDE;
+ virtual fileapi::FileSystemQuotaUtil* GetQuotaUtil() OVERRIDE;
+ virtual void DeleteFileSystem(
+ const GURL& origin_url,
+ fileapi::FileSystemType type,
+ fileapi::FileSystemContext* context,
+ const DeleteFileSystemCallback& callback) OVERRIDE;
+
+ private:
+ // Store the profile path. We need this to create temporary snapshot files.
+ const base::FilePath profile_path_;
+
+ scoped_ptr<MediaPathFilter> media_path_filter_;
+ scoped_ptr<fileapi::CopyOrMoveFileValidatorFactory>
+ media_copy_or_move_file_validator_factory_;
+
+ scoped_ptr<fileapi::AsyncFileUtilAdapter> native_media_file_util_;
+#if defined(SUPPORT_MTP_DEVICE_FILESYSTEM)
+ scoped_ptr<DeviceMediaAsyncFileUtil> device_media_async_file_util_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(MediaFileSystemMountPointProvider);
+};
+
+} // namespace chrome
+
+#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MEDIA_FILE_SYSTEM_MOUNT_POINT_PROVIDER_H_
diff --git a/chrome/browser/media_galleries/fileapi/media_path_filter.cc b/chrome/browser/media_galleries/fileapi/media_path_filter.cc
new file mode 100644
index 0000000..98f281b
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/media_path_filter.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/string_util.h"
+#include "net/base/mime_util.h"
+
+namespace chrome {
+
+namespace {
+
+const base::FilePath::CharType* const kExtraSupportedExtensions[] = {
+ FILE_PATH_LITERAL("3gp"),
+ FILE_PATH_LITERAL("3gpp"),
+ FILE_PATH_LITERAL("avi"),
+ FILE_PATH_LITERAL("flv"),
+ FILE_PATH_LITERAL("mov"),
+ FILE_PATH_LITERAL("mpeg"),
+ FILE_PATH_LITERAL("mpeg4"),
+ FILE_PATH_LITERAL("mpegps"),
+ FILE_PATH_LITERAL("mpg"),
+ FILE_PATH_LITERAL("wmv"),
+};
+
+bool IsUnsupportedExtension(const base::FilePath::StringType& extension) {
+ std::string mime_type;
+ return !net::GetMimeTypeFromExtension(extension, &mime_type) ||
+ !net::IsSupportedMimeType(mime_type);
+}
+
+} // namespace
+
+MediaPathFilter::MediaPathFilter()
+ : initialized_(false) {
+}
+
+MediaPathFilter::~MediaPathFilter() {
+}
+
+bool MediaPathFilter::Match(const base::FilePath& path) {
+ EnsureInitialized();
+ return std::binary_search(media_file_extensions_.begin(),
+ media_file_extensions_.end(),
+ StringToLowerASCII(path.Extension()));
+}
+
+void MediaPathFilter::EnsureInitialized() {
+ if (initialized_)
+ return;
+
+ base::AutoLock lock(initialization_lock_);
+ if (initialized_)
+ return;
+
+ net::GetExtensionsForMimeType("image/*", &media_file_extensions_);
+ net::GetExtensionsForMimeType("audio/*", &media_file_extensions_);
+ net::GetExtensionsForMimeType("video/*", &media_file_extensions_);
+
+ MediaFileExtensionList::iterator new_end =
+ std::remove_if(media_file_extensions_.begin(),
+ media_file_extensions_.end(),
+ &IsUnsupportedExtension);
+ media_file_extensions_.erase(new_end, media_file_extensions_.end());
+
+ // Add other common extensions.
+ for (size_t i = 0; i < arraysize(kExtraSupportedExtensions); ++i)
+ media_file_extensions_.push_back(kExtraSupportedExtensions[i]);
+
+ for (MediaFileExtensionList::iterator itr = media_file_extensions_.begin();
+ itr != media_file_extensions_.end(); ++itr)
+ *itr = base::FilePath::kExtensionSeparator + *itr;
+ std::sort(media_file_extensions_.begin(), media_file_extensions_.end());
+
+ initialized_ = true;
+}
+
+} // namespace chrome
diff --git a/chrome/browser/media_galleries/fileapi/media_path_filter.h b/chrome/browser/media_galleries/fileapi/media_path_filter.h
new file mode 100644
index 0000000..c74d4d3
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/media_path_filter.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MEDIA_PATH_FILTER_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MEDIA_PATH_FILTER_H_
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace chrome {
+
+// This class holds the list of file path extensions that we should expose on
+// media filesystem.
+class MediaPathFilter {
+ public:
+ MediaPathFilter();
+ ~MediaPathFilter();
+ bool Match(const base::FilePath& path);
+
+ private:
+ typedef std::vector<base::FilePath::StringType> MediaFileExtensionList;
+
+ void EnsureInitialized();
+
+ bool initialized_;
+ base::Lock initialization_lock_;
+ MediaFileExtensionList media_file_extensions_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaPathFilter);
+};
+
+} // namespace chrome
+
+#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MEDIA_PATH_FILTER_H_
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
new file mode 100644
index 0000000..ba07d37
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MTP_DEVICE_ASYNC_DELEGATE_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MTP_DEVICE_ASYNC_DELEGATE_H_
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/platform_file.h"
+#include "webkit/fileapi/async_file_util.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace chrome {
+
+// Asynchronous delegate for media transfer protocol (MTP) device to perform
+// media device isolated file system operations. Class that implements this
+// delegate does the actual communication with the MTP device.
+// ScopedMTPDeviceMapEntry class manages the lifetime of the delegate via
+// MTPDeviceMapService class. Member functions and callbacks runs on the IO
+// thread.
+class MTPDeviceAsyncDelegate {
+ public:
+ // A callback to be called when GetFileInfo method call succeeds.
+ typedef base::Callback<
+ void(const base::PlatformFileInfo& file_info)> GetFileInfoSuccessCallback;
+
+ // A callback to be called when ReadDirectory method call succeeds.
+ typedef base::Callback<
+ void(const fileapi::AsyncFileUtil::EntryList& file_list,
+ bool has_more)> ReadDirectorySuccessCallback;
+
+ // A callback to be called when GetFileInfo/ReadDirectory/CreateSnapshot
+ // method call fails.
+ typedef base::Callback<
+ void(base::PlatformFileError error)> ErrorCallback;
+
+ // A callback to be called when CreateSnapshotFile method call succeeds.
+ typedef base::Callback<
+ void(const base::PlatformFileInfo& file_info,
+ const base::FilePath& local_path)> CreateSnapshotFileSuccessCallback;
+
+ // Gets information about the given |file_path| and invokes the appropriate
+ // callback asynchronously when complete.
+ virtual void GetFileInfo(
+ const base::FilePath& file_path,
+ const GetFileInfoSuccessCallback& success_callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Enumerates the |root| directory contents and invokes the appropriate
+ // callback asynchronously when complete.
+ virtual void ReadDirectory(
+ const base::FilePath& root,
+ const ReadDirectorySuccessCallback& success_callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Copy the contents of |device_file_path| to |local_path|. Invokes the
+ // appropriate callback asynchronously when complete.
+ virtual void CreateSnapshotFile(
+ const base::FilePath& device_file_path,
+ const base::FilePath& local_path,
+ const CreateSnapshotFileSuccessCallback& success_callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Called when the
+ // (1) Browser application is in shutdown mode (or)
+ // (2) Last extension using this MTP device is destroyed (or)
+ // (3) Attached MTP device is removed (or)
+ // (4) User revoked the MTP device gallery permission.
+ // Ownership of |MTPDeviceAsyncDelegate| is handed off to the delegate
+ // implementation class by this call. This function should take care of
+ // cancelling all the pending tasks before deleting itself.
+ virtual void CancelPendingTasksAndDeleteDelegate() = 0;
+
+ protected:
+ // Always destruct this object via CancelPendingTasksAndDeleteDelegate().
+ virtual ~MTPDeviceAsyncDelegate() {}
+};
+
+} // namespace chrome
+
+#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MTP_DEVICE_ASYNC_DELEGATE_H_
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_file_system_config.h b/chrome/browser/media_galleries/fileapi/mtp_device_file_system_config.h
new file mode 100644
index 0000000..1877de8
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/mtp_device_file_system_config.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MTP_DEVICE_FILE_SYSTEM_CONFIG_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MTP_DEVICE_FILE_SYSTEM_CONFIG_H_
+
+#include "build/build_config.h"
+
+// Support MTP device file system for Windows, Mac, Linux and ChromeOS.
+// Note that OS_LINUX implies OS_CHROMEOS.
+// TODO(gbillock): remove this define and make this default.
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
+#define SUPPORT_MTP_DEVICE_FILESYSTEM
+#endif
+
+#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MTP_DEVICE_FILE_SYSTEM_CONFIG_H_
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc
new file mode 100644
index 0000000..96c5b85
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h"
+
+#include <string>
+#include <utility>
+
+#include "base/stl_util.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
+#include "webkit/fileapi/isolated_context.h"
+
+namespace chrome {
+
+namespace {
+
+base::LazyInstance<MTPDeviceMapService> g_mtp_device_map_service =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+// static
+MTPDeviceMapService* MTPDeviceMapService::GetInstance() {
+ return g_mtp_device_map_service.Pointer();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Following methods are used to manage MTPDeviceAsyncDelegate objects. //
+/////////////////////////////////////////////////////////////////////////////
+void MTPDeviceMapService::AddAsyncDelegate(
+ const base::FilePath::StringType& device_location,
+ MTPDeviceAsyncDelegate* delegate) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(delegate);
+ DCHECK(!device_location.empty());
+ if (ContainsKey(async_delegate_map_, device_location))
+ return;
+ async_delegate_map_[device_location] = delegate;
+}
+
+void MTPDeviceMapService::RemoveAsyncDelegate(
+ const base::FilePath::StringType& device_location) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ AsyncDelegateMap::iterator it = async_delegate_map_.find(device_location);
+ DCHECK(it != async_delegate_map_.end());
+ it->second->CancelPendingTasksAndDeleteDelegate();
+ async_delegate_map_.erase(it);
+}
+
+MTPDeviceAsyncDelegate* MTPDeviceMapService::GetMTPDeviceAsyncDelegate(
+ const std::string& filesystem_id) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ base::FilePath device_path;
+ if (!fileapi::IsolatedContext::GetInstance()->GetRegisteredPath(
+ filesystem_id, &device_path)) {
+ return NULL;
+ }
+
+ const base::FilePath::StringType& device_location = device_path.value();
+ DCHECK(!device_location.empty());
+ AsyncDelegateMap::const_iterator it =
+ async_delegate_map_.find(device_location);
+ return (it != async_delegate_map_.end()) ? it->second : NULL;
+}
+
+
+MTPDeviceMapService::MTPDeviceMapService() {
+}
+
+MTPDeviceMapService::~MTPDeviceMapService() {}
+
+} // namespace chrome
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h
new file mode 100644
index 0000000..18b974f5
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MTP_DEVICE_MAP_SERVICE_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MTP_DEVICE_MAP_SERVICE_H_
+
+#include <map>
+
+#include "base/files/file_path.h"
+#include "base/lazy_instance.h"
+#include "base/threading/thread_checker.h"
+
+namespace chrome {
+
+class MTPDeviceAsyncDelegate;
+
+// This class provides media transfer protocol (MTP) device delegate to
+// complete media file system operations. ScopedMTPDeviceMapEntry class
+// manages the device map entries.
+class MTPDeviceMapService {
+ public:
+ static MTPDeviceMapService* GetInstance();
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Following methods are used to manage MTPDeviceAsyncDelegate objects. //
+ /////////////////////////////////////////////////////////////////////////////
+ // Adds the MTP device delegate to the map service. |device_location|
+ // specifies the mount location of the MTP device.
+ // Called on the IO thread.
+ void AddAsyncDelegate(const base::FilePath::StringType& device_location,
+ MTPDeviceAsyncDelegate* delegate);
+
+ // Removes the MTP device delegate from the map service. |device_location|
+ // specifies the mount location of the MTP device.
+ // Called on the IO thread.
+ void RemoveAsyncDelegate(const base::FilePath::StringType& device_location);
+
+ // Gets the media device delegate associated with |filesystem_id|.
+ // Return NULL if the |filesystem_id| is no longer valid (e.g. because the
+ // corresponding device is detached, etc).
+ // Called on the IO thread.
+ MTPDeviceAsyncDelegate* GetMTPDeviceAsyncDelegate(
+ const std::string& filesystem_id);
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<MTPDeviceMapService>;
+
+ // Mapping of device_location and MTPDeviceAsyncDelegate* object. It is safe
+ // to store and access the raw pointer. This class operates on the IO thread.
+ typedef std::map<base::FilePath::StringType, MTPDeviceAsyncDelegate*>
+ AsyncDelegateMap;
+
+ // Get access to this class using GetInstance() method.
+ MTPDeviceMapService();
+ ~MTPDeviceMapService();
+
+ /////////////////////////////////////////////////////////////////////////////
+ // Following member variables are used to manage asynchronous //
+ // MTP device delegate objects. //
+ /////////////////////////////////////////////////////////////////////////////
+ // Map of attached mtp device async delegates.
+ AsyncDelegateMap async_delegate_map_;
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(MTPDeviceMapService);
+};
+
+} // namespace chrome
+
+#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MTP_DEVICE_MAP_SERVICE_H_
diff --git a/chrome/browser/media_galleries/fileapi/native_media_file_util.cc b/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
new file mode 100644
index 0000000..19724f9
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
@@ -0,0 +1,229 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
+
+#include "chrome/browser/media_galleries/fileapi/filtering_file_enumerator.h"
+#include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h"
+#include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
+#include "webkit/fileapi/file_system_operation_context.h"
+#include "webkit/fileapi/native_file_util.h"
+
+using base::PlatformFile;
+using base::PlatformFileError;
+using base::PlatformFileInfo;
+using fileapi::FileSystemOperationContext;
+using fileapi::FileSystemURL;
+using fileapi::NativeFileUtil;
+
+namespace chrome {
+
+namespace {
+
+MediaPathFilter* GetMediaPathFilter(FileSystemOperationContext* context) {
+ return context->GetUserValue<MediaPathFilter*>(
+ MediaFileSystemMountPointProvider::kMediaPathFilterKey);
+}
+
+} // namespace
+
+NativeMediaFileUtil::NativeMediaFileUtil() {
+}
+
+PlatformFileError NativeMediaFileUtil::CreateOrOpen(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ int file_flags,
+ PlatformFile* file_handle,
+ bool* created) {
+ // Only called by NaCl, which should not have access to media file systems.
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+}
+
+PlatformFileError NativeMediaFileUtil::EnsureFileExists(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url, bool* created) {
+ base::FilePath file_path;
+ PlatformFileError error = GetFilteredLocalFilePath(context, url, &file_path);
+ if (error != base::PLATFORM_FILE_OK)
+ return error;
+ return NativeFileUtil::EnsureFileExists(file_path, created);
+}
+
+scoped_ptr<fileapi::FileSystemFileUtil::AbstractFileEnumerator>
+NativeMediaFileUtil::CreateFileEnumerator(
+ FileSystemOperationContext* context,
+ const FileSystemURL& root_url) {
+ DCHECK(context);
+ return make_scoped_ptr(new FilteringFileEnumerator(
+ IsolatedFileUtil::CreateFileEnumerator(context, root_url),
+ GetMediaPathFilter(context)))
+ .PassAs<FileSystemFileUtil::AbstractFileEnumerator>();
+}
+
+PlatformFileError NativeMediaFileUtil::Touch(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time) {
+ base::FilePath file_path;
+ PlatformFileError error = GetFilteredLocalFilePathForExistingFileOrDirectory(
+ context,
+ url,
+ // Touch fails for non-existent paths and filtered paths.
+ base::PLATFORM_FILE_ERROR_FAILED,
+ &file_path);
+ if (error != base::PLATFORM_FILE_OK)
+ return error;
+ return NativeFileUtil::Touch(file_path, last_access_time, last_modified_time);
+}
+
+PlatformFileError NativeMediaFileUtil::Truncate(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ int64 length) {
+ base::FilePath file_path;
+ PlatformFileError error = GetFilteredLocalFilePathForExistingFileOrDirectory(
+ context,
+ url,
+ // Cannot truncate paths that do not exist, or are filtered.
+ base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ &file_path);
+ if (error != base::PLATFORM_FILE_OK)
+ return error;
+ return NativeFileUtil::Truncate(file_path, length);
+}
+
+PlatformFileError NativeMediaFileUtil::CopyOrMoveFile(
+ FileSystemOperationContext* context,
+ const FileSystemURL& src_url,
+ const FileSystemURL& dest_url,
+ bool copy) {
+ base::FilePath src_file_path;
+ PlatformFileError error =
+ GetFilteredLocalFilePathForExistingFileOrDirectory(
+ context, src_url,
+ base::PLATFORM_FILE_ERROR_NOT_FOUND,
+ &src_file_path);
+ if (error != base::PLATFORM_FILE_OK)
+ return error;
+ if (NativeFileUtil::DirectoryExists(src_file_path))
+ return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
+
+ base::FilePath dest_file_path;
+ error = GetLocalFilePath(context, dest_url, &dest_file_path);
+ if (error != base::PLATFORM_FILE_OK)
+ return error;
+ PlatformFileInfo file_info;
+ error = NativeFileUtil::GetFileInfo(dest_file_path, &file_info);
+ if (error != base::PLATFORM_FILE_OK &&
+ error != base::PLATFORM_FILE_ERROR_NOT_FOUND)
+ return error;
+ if (error == base::PLATFORM_FILE_OK && file_info.is_directory)
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ if (!GetMediaPathFilter(context)->Match(dest_file_path))
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+
+ return NativeFileUtil::CopyOrMoveFile(src_file_path, dest_file_path, copy);
+}
+
+PlatformFileError NativeMediaFileUtil::CopyInForeignFile(
+ FileSystemOperationContext* context,
+ const base::FilePath& src_file_path,
+ const FileSystemURL& dest_url) {
+ if (src_file_path.empty())
+ return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+
+ base::FilePath dest_file_path;
+ PlatformFileError error =
+ GetFilteredLocalFilePath(context, dest_url, &dest_file_path);
+ if (error != base::PLATFORM_FILE_OK)
+ return error;
+ return NativeFileUtil::CopyOrMoveFile(src_file_path, dest_file_path, true);
+}
+
+PlatformFileError NativeMediaFileUtil::DeleteFile(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url) {
+ base::FilePath file_path;
+ PlatformFileError error = GetLocalFilePath(context, url, &file_path);
+ if (error != base::PLATFORM_FILE_OK)
+ return error;
+ PlatformFileInfo file_info;
+ error = NativeFileUtil::GetFileInfo(file_path, &file_info);
+ if (error != base::PLATFORM_FILE_OK)
+ return error;
+ if (file_info.is_directory)
+ return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
+ if (!GetMediaPathFilter(context)->Match(file_path))
+ return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+ return NativeFileUtil::DeleteFile(file_path);
+}
+
+PlatformFileError NativeMediaFileUtil::GetFileInfo(
+ FileSystemOperationContext* context,
+ const FileSystemURL& url,
+ PlatformFileInfo* file_info,
+ base::FilePath* platform_path) {
+ DCHECK(context);
+ DCHECK(GetMediaPathFilter(context));
+ DCHECK(file_info);
+ DCHECK(platform_path);
+
+ base::PlatformFileError error =
+ IsolatedFileUtil::GetFileInfo(context, url, file_info, platform_path);
+ if (error != base::PLATFORM_FILE_OK)
+ return error;
+
+ if (file_info->is_directory ||
+ GetMediaPathFilter(context)->Match(*platform_path)) {
+ return base::PLATFORM_FILE_OK;
+ }
+ return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+}
+
+PlatformFileError NativeMediaFileUtil::GetFilteredLocalFilePath(
+ FileSystemOperationContext* context,
+ const FileSystemURL& file_system_url,
+ base::FilePath* local_file_path) {
+ base::FilePath file_path;
+ PlatformFileError error =
+ IsolatedFileUtil::GetLocalFilePath(context, file_system_url, &file_path);
+ if (error != base::PLATFORM_FILE_OK)
+ return error;
+ if (!GetMediaPathFilter(context)->Match(file_path))
+ return base::PLATFORM_FILE_ERROR_SECURITY;
+
+ *local_file_path = file_path;
+ return base::PLATFORM_FILE_OK;
+}
+
+PlatformFileError
+NativeMediaFileUtil::GetFilteredLocalFilePathForExistingFileOrDirectory(
+ FileSystemOperationContext* context,
+ const FileSystemURL& file_system_url,
+ PlatformFileError failure_error,
+ base::FilePath* local_file_path) {
+ base::FilePath file_path;
+ PlatformFileError error =
+ GetLocalFilePath(context, file_system_url, &file_path);
+ if (error != base::PLATFORM_FILE_OK)
+ return error;
+
+ if (!file_util::PathExists(file_path))
+ return failure_error;
+ PlatformFileInfo file_info;
+ if (!file_util::GetFileInfo(file_path, &file_info))
+ return base::PLATFORM_FILE_ERROR_FAILED;
+
+ if (!file_info.is_directory &&
+ !GetMediaPathFilter(context)->Match(file_path)) {
+ return failure_error;
+ }
+
+ *local_file_path = file_path;
+ return base::PLATFORM_FILE_OK;
+}
+
+} // namespace chrome
diff --git a/chrome/browser/media_galleries/fileapi/native_media_file_util.h b/chrome/browser/media_galleries/fileapi/native_media_file_util.h
new file mode 100644
index 0000000..aa4ee62
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/native_media_file_util.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_NATIVE_MEDIA_FILE_UTIL_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_NATIVE_MEDIA_FILE_UTIL_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "webkit/fileapi/isolated_file_util.h"
+
+namespace chrome {
+
+// This class handles native file system operations with media type filtering
+// which is passed to each method via fileapi::FileSystemOperationContext as
+// MediaPathFilter.
+class NativeMediaFileUtil : public fileapi::IsolatedFileUtil {
+ public:
+ NativeMediaFileUtil();
+
+ virtual base::PlatformFileError CreateOrOpen(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ int file_flags,
+ base::PlatformFile* file_handle,
+ bool* created) OVERRIDE;
+ virtual base::PlatformFileError EnsureFileExists(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url, bool* created) OVERRIDE;
+ virtual scoped_ptr<AbstractFileEnumerator> CreateFileEnumerator(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& root_url) OVERRIDE;
+ virtual base::PlatformFileError Touch(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ const base::Time& last_access_time,
+ const base::Time& last_modified_time) OVERRIDE;
+ virtual base::PlatformFileError Truncate(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ int64 length) OVERRIDE;
+ virtual base::PlatformFileError CopyOrMoveFile(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& src_url,
+ const fileapi::FileSystemURL& dest_url,
+ bool copy) OVERRIDE;
+ virtual base::PlatformFileError CopyInForeignFile(
+ fileapi::FileSystemOperationContext* context,
+ const base::FilePath& src_file_path,
+ const fileapi::FileSystemURL& dest_url) OVERRIDE;
+ virtual base::PlatformFileError DeleteFile(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url) OVERRIDE;
+ virtual base::PlatformFileError GetFileInfo(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& url,
+ base::PlatformFileInfo* file_info,
+ base::FilePath* platform_path) OVERRIDE;
+
+ private:
+ // Like GetLocalFilePath(), but always take media_path_filter() into
+ // consideration. If the media_path_filter() check fails, return
+ // PLATFORM_FILE_ERROR_SECURITY. |local_file_path| does not have to exist.
+ base::PlatformFileError GetFilteredLocalFilePath(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& file_system_url,
+ base::FilePath* local_file_path);
+
+ // Like GetLocalFilePath(), but if the file does not exist, then return
+ // |failure_error|.
+ // If |local_file_path| is a file, then take media_path_filter() into
+ // consideration.
+ // If the media_path_filter() check fails, return |failure_error|.
+ // If |local_file_path| is a directory, return PLATFORM_FILE_OK.
+ base::PlatformFileError GetFilteredLocalFilePathForExistingFileOrDirectory(
+ fileapi::FileSystemOperationContext* context,
+ const fileapi::FileSystemURL& file_system_url,
+ base::PlatformFileError failure_error,
+ base::FilePath* local_file_path);
+
+ DISALLOW_COPY_AND_ASSIGN(NativeMediaFileUtil);
+};
+
+} // namespace chrome
+
+#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_NATIVE_MEDIA_FILE_UTIL_H_
diff --git a/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc b/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc
new file mode 100644
index 0000000..32de0e4
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc
@@ -0,0 +1,614 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <set>
+#include <string>
+
+#include "base/bind.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/format_macros.h"
+#include "base/message_loop.h"
+#include "base/stringprintf.h"
+#include "base/time.h"
+#include "chrome/browser/media_galleries/fileapi/media_file_system_mount_point_provider.h"
+#include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/fileapi/external_mount_points.h"
+#include "webkit/fileapi/file_system_context.h"
+#include "webkit/fileapi/file_system_mount_point_provider.h"
+#include "webkit/fileapi/file_system_operation.h"
+#include "webkit/fileapi/file_system_task_runners.h"
+#include "webkit/fileapi/file_system_url.h"
+#include "webkit/fileapi/isolated_context.h"
+#include "webkit/fileapi/mock_file_system_options.h"
+#include "webkit/fileapi/native_file_util.h"
+#include "webkit/quota/mock_special_storage_policy.h"
+
+#define FPL(x) FILE_PATH_LITERAL(x)
+
+using fileapi::FileSystemOperation;
+using fileapi::FileSystemURL;
+
+namespace chrome {
+
+namespace {
+
+typedef FileSystemOperation::FileEntryList FileEntryList;
+
+struct FilteringTestCase {
+ const base::FilePath::CharType* path;
+ bool is_directory;
+ bool visible;
+};
+
+const FilteringTestCase kFilteringTestCases[] = {
+ // Directory should always be visible.
+ { FPL("hoge"), true, true },
+ { FPL("fuga.jpg"), true, true },
+ { FPL("piyo.txt"), true, true },
+ { FPL("moga.cod"), true, true },
+
+ // File should be visible if it's a supported media file.
+ { FPL("foo"), false, false }, // File without extension.
+ { FPL("bar.jpg"), false, true }, // Supported media file.
+ { FPL("baz.txt"), false, false }, // Non-media file.
+ { FPL("foobar.cod"), false, false }, // Unsupported media file.
+};
+
+void ExpectEqHelper(const std::string& test_name,
+ base::PlatformFileError expected,
+ base::PlatformFileError actual) {
+ EXPECT_EQ(expected, actual) << test_name;
+}
+
+void ExpectMetadataEqHelper(const std::string& test_name,
+ base::PlatformFileError expected,
+ bool expected_is_directory,
+ base::PlatformFileError actual,
+ const base::PlatformFileInfo& file_info,
+ const base::FilePath& /*platform_path*/) {
+ EXPECT_EQ(expected, actual) << test_name;
+ if (actual == base::PLATFORM_FILE_OK)
+ EXPECT_EQ(expected_is_directory, file_info.is_directory) << test_name;
+}
+
+void DidReadDirectory(std::set<base::FilePath::StringType>* content,
+ bool* completed,
+ base::PlatformFileError error,
+ const FileEntryList& file_list,
+ bool has_more) {
+ EXPECT_TRUE(!*completed);
+ *completed = !has_more;
+ for (FileEntryList::const_iterator itr = file_list.begin();
+ itr != file_list.end(); ++itr)
+ EXPECT_TRUE(content->insert(itr->name).second);
+}
+
+void PopulateDirectoryWithTestCases(const base::FilePath& dir,
+ const FilteringTestCase* test_cases,
+ size_t n) {
+ for (size_t i = 0; i < n; ++i) {
+ base::FilePath path = dir.Append(test_cases[i].path);
+ if (test_cases[i].is_directory) {
+ ASSERT_TRUE(file_util::CreateDirectory(path));
+ } else {
+ bool created = false;
+ ASSERT_EQ(base::PLATFORM_FILE_OK,
+ fileapi::NativeFileUtil::EnsureFileExists(path, &created));
+ ASSERT_TRUE(created);
+ }
+ }
+}
+
+} // namespace
+
+class NativeMediaFileUtilTest : public testing::Test {
+ public:
+ NativeMediaFileUtilTest()
+ : file_util_(NULL) {
+ }
+
+ virtual void SetUp() {
+ ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
+ ASSERT_TRUE(file_util::CreateDirectory(root_path()));
+
+ scoped_refptr<quota::SpecialStoragePolicy> storage_policy =
+ new quota::MockSpecialStoragePolicy();
+
+ ScopedVector<fileapi::FileSystemMountPointProvider> additional_providers;
+ additional_providers.push_back(new MediaFileSystemMountPointProvider(
+ data_dir_.path()));
+
+ file_system_context_ =
+ new fileapi::FileSystemContext(
+ fileapi::FileSystemTaskRunners::CreateMockTaskRunners(),
+ fileapi::ExternalMountPoints::CreateRefCounted().get(),
+ storage_policy,
+ NULL,
+ additional_providers.Pass(),
+ data_dir_.path(),
+ fileapi::CreateAllowFileAccessOptions());
+
+ file_util_ = file_system_context_->GetFileUtil(
+ fileapi::kFileSystemTypeNativeMedia);
+
+ filesystem_id_ = isolated_context()->RegisterFileSystemForPath(
+ fileapi::kFileSystemTypeNativeMedia, root_path(), NULL);
+
+ isolated_context()->AddReference(filesystem_id_);
+ }
+
+ virtual void TearDown() {
+ isolated_context()->RemoveReference(filesystem_id_);
+ file_system_context_ = NULL;
+ }
+
+ protected:
+ fileapi::FileSystemContext* file_system_context() {
+ return file_system_context_.get();
+ }
+
+ FileSystemURL CreateURL(const base::FilePath::CharType* test_case_path) {
+ return file_system_context_->CreateCrackedFileSystemURL(
+ origin(),
+ fileapi::kFileSystemTypeIsolated,
+ GetVirtualPath(test_case_path));
+ }
+
+ fileapi::IsolatedContext* isolated_context() {
+ return fileapi::IsolatedContext::GetInstance();
+ }
+
+ base::FilePath root_path() {
+ return data_dir_.path().Append(FPL("Media Directory"));
+ }
+
+ base::FilePath GetVirtualPath(
+ const base::FilePath::CharType* test_case_path) {
+ return base::FilePath::FromUTF8Unsafe(filesystem_id_).
+ Append(FPL("Media Directory")).
+ Append(base::FilePath(test_case_path));
+ }
+
+ fileapi::FileSystemFileUtil* file_util() {
+ return file_util_;
+ }
+
+ GURL origin() {
+ return GURL("http://example.com");
+ }
+
+ fileapi::FileSystemType type() {
+ return fileapi::kFileSystemTypeNativeMedia;
+ }
+
+ FileSystemOperation* NewOperation(const FileSystemURL& url) {
+ return file_system_context_->CreateFileSystemOperation(url, NULL);
+ }
+
+ private:
+ MessageLoop message_loop_;
+
+ base::ScopedTempDir data_dir_;
+ scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+
+ fileapi::FileSystemFileUtil* file_util_;
+ std::string filesystem_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeMediaFileUtilTest);
+};
+
+TEST_F(NativeMediaFileUtilTest, DirectoryExistsAndFileExistsFiltering) {
+ PopulateDirectoryWithTestCases(root_path(),
+ kFilteringTestCases,
+ arraysize(kFilteringTestCases));
+
+ for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
+ FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
+ FileSystemOperation* operation = NewOperation(url);
+
+ base::PlatformFileError expectation =
+ kFilteringTestCases[i].visible ?
+ base::PLATFORM_FILE_OK :
+ base::PLATFORM_FILE_ERROR_NOT_FOUND;
+
+ std::string test_name =
+ base::StringPrintf("DirectoryExistsAndFileExistsFiltering %" PRIuS, i);
+ if (kFilteringTestCases[i].is_directory) {
+ operation->DirectoryExists(
+ url, base::Bind(&ExpectEqHelper, test_name, expectation));
+ } else {
+ operation->FileExists(
+ url, base::Bind(&ExpectEqHelper, test_name, expectation));
+ }
+ MessageLoop::current()->RunUntilIdle();
+ }
+}
+
+TEST_F(NativeMediaFileUtilTest, ReadDirectoryFiltering) {
+ PopulateDirectoryWithTestCases(root_path(),
+ kFilteringTestCases,
+ arraysize(kFilteringTestCases));
+
+ std::set<base::FilePath::StringType> content;
+ FileSystemURL url = CreateURL(FPL(""));
+ bool completed = false;
+ NewOperation(url)->ReadDirectory(
+ url, base::Bind(&DidReadDirectory, &content, &completed));
+ MessageLoop::current()->RunUntilIdle();
+ EXPECT_TRUE(completed);
+ EXPECT_EQ(5u, content.size());
+
+ for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
+ base::FilePath::StringType name =
+ base::FilePath(kFilteringTestCases[i].path).BaseName().value();
+ std::set<base::FilePath::StringType>::const_iterator found =
+ content.find(name);
+ EXPECT_EQ(kFilteringTestCases[i].visible, found != content.end());
+ }
+}
+
+TEST_F(NativeMediaFileUtilTest, CreateFileAndCreateDirectoryFiltering) {
+ // Run the loop twice. The second loop attempts to create files that are
+ // pre-existing. Though the result should be the same.
+ for (int loop_count = 0; loop_count < 2; ++loop_count) {
+ for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
+ FileSystemURL root_url = CreateURL(FPL(""));
+ FileSystemOperation* operation = NewOperation(root_url);
+
+ FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
+
+ std::string test_name = base::StringPrintf(
+ "CreateFileAndCreateDirectoryFiltering run %d, test %" PRIuS,
+ loop_count, i);
+ base::PlatformFileError expectation =
+ kFilteringTestCases[i].visible ?
+ base::PLATFORM_FILE_OK :
+ base::PLATFORM_FILE_ERROR_SECURITY;
+ if (kFilteringTestCases[i].is_directory) {
+ operation->CreateDirectory(
+ url, false, false,
+ base::Bind(&ExpectEqHelper, test_name, expectation));
+ } else {
+ operation->CreateFile(
+ url, false, base::Bind(&ExpectEqHelper, test_name, expectation));
+ }
+ MessageLoop::current()->RunUntilIdle();
+ }
+ }
+}
+
+TEST_F(NativeMediaFileUtilTest, CopySourceFiltering) {
+ base::FilePath dest_path = root_path().AppendASCII("dest");
+ FileSystemURL dest_url = CreateURL(FPL("dest"));
+
+ // Run the loop twice. The first run has no source files. The second run does.
+ for (int loop_count = 0; loop_count < 2; ++loop_count) {
+ if (loop_count == 1) {
+ PopulateDirectoryWithTestCases(root_path(),
+ kFilteringTestCases,
+ arraysize(kFilteringTestCases));
+ }
+ for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
+ // Always start with an empty destination directory.
+ // Copying to a non-empty destination directory is an invalid operation.
+ ASSERT_TRUE(file_util::Delete(dest_path, true));
+ ASSERT_TRUE(file_util::CreateDirectory(dest_path));
+
+ FileSystemURL root_url = CreateURL(FPL(""));
+ FileSystemOperation* operation = NewOperation(root_url);
+
+ FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
+
+ std::string test_name = base::StringPrintf(
+ "CopySourceFiltering run %d test %" PRIuS, loop_count, i);
+ base::PlatformFileError expectation = base::PLATFORM_FILE_OK;
+ if (loop_count == 0 || !kFilteringTestCases[i].visible) {
+ // If the source does not exist or is not visible.
+ expectation = base::PLATFORM_FILE_ERROR_NOT_FOUND;
+ } else if (!kFilteringTestCases[i].is_directory) {
+ // Cannot copy a visible file to a directory.
+ expectation = base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ }
+ operation->Copy(
+ url, dest_url, base::Bind(&ExpectEqHelper, test_name, expectation));
+ MessageLoop::current()->RunUntilIdle();
+ }
+ }
+}
+
+TEST_F(NativeMediaFileUtilTest, CopyDestFiltering) {
+ // Run the loop twice. The first run has no destination files.
+ // The second run does.
+ for (int loop_count = 0; loop_count < 2; ++loop_count) {
+ if (loop_count == 1) {
+ // Reset the test directory between the two loops to remove old
+ // directories and create new ones that should pre-exist.
+ ASSERT_TRUE(file_util::Delete(root_path(), true));
+ ASSERT_TRUE(file_util::CreateDirectory(root_path()));
+ PopulateDirectoryWithTestCases(root_path(),
+ kFilteringTestCases,
+ arraysize(kFilteringTestCases));
+ }
+
+ // Always create a dummy source data file.
+ base::FilePath src_path = root_path().AppendASCII("foo.jpg");
+ FileSystemURL src_url = CreateURL(FPL("foo.jpg"));
+ static const char kDummyData[] = "dummy";
+ ASSERT_TRUE(file_util::WriteFile(src_path, kDummyData, strlen(kDummyData)));
+
+ for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
+ if (loop_count == 0 && kFilteringTestCases[i].is_directory) {
+ // These directories do not exist in this case, so Copy() will not
+ // treat them as directories. Thus invalidating these test cases.
+ // Continue now to avoid creating a new |operation| below that goes
+ // unused.
+ continue;
+ }
+ FileSystemURL root_url = CreateURL(FPL(""));
+ FileSystemOperation* operation = NewOperation(root_url);
+
+ FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
+
+ std::string test_name = base::StringPrintf(
+ "CopyDestFiltering run %d test %" PRIuS, loop_count, i);
+ base::PlatformFileError expectation;
+ if (loop_count == 0) {
+ // The destination path is a file here. The directory case has been
+ // handled above.
+ // If the destination path does not exist and is not visible, then
+ // creating it would be a security violation.
+ expectation =
+ kFilteringTestCases[i].visible ?
+ base::PLATFORM_FILE_OK :
+ base::PLATFORM_FILE_ERROR_SECURITY;
+ } else {
+ if (!kFilteringTestCases[i].visible) {
+ // If the destination path exist and is not visible, then to the copy
+ // operation, it looks like the file needs to be created, which is a
+ // security violation.
+ expectation = base::PLATFORM_FILE_ERROR_SECURITY;
+ } else if (kFilteringTestCases[i].is_directory) {
+ // Cannot copy a file to a directory.
+ expectation = base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ } else {
+ // Copying from a file to a visible file that exists is ok.
+ expectation = base::PLATFORM_FILE_OK;
+ }
+ }
+ operation->Copy(
+ src_url, url, base::Bind(&ExpectEqHelper, test_name, expectation));
+ MessageLoop::current()->RunUntilIdle();
+ }
+ }
+}
+
+TEST_F(NativeMediaFileUtilTest, MoveSourceFiltering) {
+ base::FilePath dest_path = root_path().AppendASCII("dest");
+ FileSystemURL dest_url = CreateURL(FPL("dest"));
+
+ // Run the loop twice. The first run has no source files. The second run does.
+ for (int loop_count = 0; loop_count < 2; ++loop_count) {
+ if (loop_count == 1) {
+ PopulateDirectoryWithTestCases(root_path(),
+ kFilteringTestCases,
+ arraysize(kFilteringTestCases));
+ }
+ for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
+ // Always start with an empty destination directory.
+ // Moving to a non-empty destination directory is an invalid operation.
+ ASSERT_TRUE(file_util::Delete(dest_path, true));
+ ASSERT_TRUE(file_util::CreateDirectory(dest_path));
+
+ FileSystemURL root_url = CreateURL(FPL(""));
+ FileSystemOperation* operation = NewOperation(root_url);
+
+ FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
+
+ std::string test_name = base::StringPrintf(
+ "MoveSourceFiltering run %d test %" PRIuS, loop_count, i);
+ base::PlatformFileError expectation = base::PLATFORM_FILE_OK;
+ if (loop_count == 0 || !kFilteringTestCases[i].visible) {
+ // If the source does not exist or is not visible.
+ expectation = base::PLATFORM_FILE_ERROR_NOT_FOUND;
+ } else if (!kFilteringTestCases[i].is_directory) {
+ // Cannot move a visible file to a directory.
+ expectation = base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ }
+ operation->Move(
+ url, dest_url, base::Bind(&ExpectEqHelper, test_name, expectation));
+ MessageLoop::current()->RunUntilIdle();
+ }
+ }
+}
+
+TEST_F(NativeMediaFileUtilTest, MoveDestFiltering) {
+ // Run the loop twice. The first run has no destination files.
+ // The second run does.
+ for (int loop_count = 0; loop_count < 2; ++loop_count) {
+ if (loop_count == 1) {
+ // Reset the test directory between the two loops to remove old
+ // directories and create new ones that should pre-exist.
+ ASSERT_TRUE(file_util::Delete(root_path(), true));
+ ASSERT_TRUE(file_util::CreateDirectory(root_path()));
+ PopulateDirectoryWithTestCases(root_path(),
+ kFilteringTestCases,
+ arraysize(kFilteringTestCases));
+ }
+
+ for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
+ if (loop_count == 0 && kFilteringTestCases[i].is_directory) {
+ // These directories do not exist in this case, so Copy() will not
+ // treat them as directories. Thus invalidating these test cases.
+ // Continue now to avoid creating a new |operation| below that goes
+ // unused.
+ continue;
+ }
+
+ // Create the source file for every test case because it might get moved.
+ base::FilePath src_path = root_path().AppendASCII("foo.jpg");
+ FileSystemURL src_url = CreateURL(FPL("foo.jpg"));
+ static const char kDummyData[] = "dummy";
+ ASSERT_TRUE(
+ file_util::WriteFile(src_path, kDummyData, strlen(kDummyData)));
+
+ FileSystemURL root_url = CreateURL(FPL(""));
+ FileSystemOperation* operation = NewOperation(root_url);
+
+ FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
+
+ std::string test_name = base::StringPrintf(
+ "MoveDestFiltering run %d test %" PRIuS, loop_count, i);
+ base::PlatformFileError expectation;
+ if (loop_count == 0) {
+ // The destination path is a file here. The directory case has been
+ // handled above.
+ // If the destination path does not exist and is not visible, then
+ // creating it would be a security violation.
+ expectation =
+ kFilteringTestCases[i].visible ?
+ base::PLATFORM_FILE_OK :
+ base::PLATFORM_FILE_ERROR_SECURITY;
+ } else {
+ if (!kFilteringTestCases[i].visible) {
+ // If the destination path exist and is not visible, then to the move
+ // operation, it looks like the file needs to be created, which is a
+ // security violation.
+ expectation = base::PLATFORM_FILE_ERROR_SECURITY;
+ } else if (kFilteringTestCases[i].is_directory) {
+ // Cannot move a file to a directory.
+ expectation = base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
+ } else {
+ // Moving from a file to a visible file that exists is ok.
+ expectation = base::PLATFORM_FILE_OK;
+ }
+ }
+ operation->Move(
+ src_url, url, base::Bind(&ExpectEqHelper, test_name, expectation));
+ MessageLoop::current()->RunUntilIdle();
+ }
+ }
+}
+
+TEST_F(NativeMediaFileUtilTest, GetMetadataFiltering) {
+ // Run the loop twice. The first run has no files. The second run does.
+ for (int loop_count = 0; loop_count < 2; ++loop_count) {
+ if (loop_count == 1) {
+ PopulateDirectoryWithTestCases(root_path(),
+ kFilteringTestCases,
+ arraysize(kFilteringTestCases));
+ }
+ for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
+ FileSystemURL root_url = CreateURL(FPL(""));
+ FileSystemOperation* operation = NewOperation(root_url);
+
+ FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
+
+ std::string test_name = base::StringPrintf(
+ "GetMetadataFiltering run %d test %" PRIuS, loop_count, i);
+ base::PlatformFileError expectation = base::PLATFORM_FILE_OK;
+ if (loop_count == 0 || !kFilteringTestCases[i].visible) {
+ // Cannot get metadata from files that do not exist or are not visible.
+ expectation = base::PLATFORM_FILE_ERROR_NOT_FOUND;
+ }
+ operation->GetMetadata(url,
+ base::Bind(&ExpectMetadataEqHelper,
+ test_name,
+ expectation,
+ kFilteringTestCases[i].is_directory));
+ MessageLoop::current()->RunUntilIdle();
+ }
+ }
+}
+
+TEST_F(NativeMediaFileUtilTest, RemoveFiltering) {
+ // Run the loop twice. The first run has no files. The second run does.
+ for (int loop_count = 0; loop_count < 2; ++loop_count) {
+ if (loop_count == 1) {
+ PopulateDirectoryWithTestCases(root_path(),
+ kFilteringTestCases,
+ arraysize(kFilteringTestCases));
+ }
+ for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
+ FileSystemURL root_url = CreateURL(FPL(""));
+ FileSystemOperation* operation = NewOperation(root_url);
+
+ FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
+
+ std::string test_name = base::StringPrintf(
+ "RemoveFiltering run %d test %" PRIuS, loop_count, i);
+ base::PlatformFileError expectation = base::PLATFORM_FILE_OK;
+ if (loop_count == 0 || !kFilteringTestCases[i].visible) {
+ // Cannot remove files that do not exist or are not visible.
+ expectation = base::PLATFORM_FILE_ERROR_NOT_FOUND;
+ }
+ operation->Remove(
+ url, false, base::Bind(&ExpectEqHelper, test_name, expectation));
+ MessageLoop::current()->RunUntilIdle();
+ }
+ }
+}
+
+TEST_F(NativeMediaFileUtilTest, TruncateFiltering) {
+ // Run the loop twice. The first run has no files. The second run does.
+ for (int loop_count = 0; loop_count < 2; ++loop_count) {
+ if (loop_count == 1) {
+ PopulateDirectoryWithTestCases(root_path(),
+ kFilteringTestCases,
+ arraysize(kFilteringTestCases));
+ }
+ for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
+ FileSystemURL root_url = CreateURL(FPL(""));
+ FileSystemOperation* operation = NewOperation(root_url);
+
+ FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
+
+ std::string test_name = base::StringPrintf(
+ "TruncateFiltering run %d test %" PRIuS, loop_count, i);
+ base::PlatformFileError expectation = base::PLATFORM_FILE_OK;
+ if (loop_count == 0 || !kFilteringTestCases[i].visible) {
+ // Cannot truncate files that do not exist or are not visible.
+ expectation = base::PLATFORM_FILE_ERROR_NOT_FOUND;
+ } else if (kFilteringTestCases[i].is_directory) {
+ // Cannot truncate directories.
+ expectation = base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
+ }
+ operation->Truncate(
+ url, 0, base::Bind(&ExpectEqHelper, test_name, expectation));
+ MessageLoop::current()->RunUntilIdle();
+ }
+ }
+}
+
+TEST_F(NativeMediaFileUtilTest, TouchFileFiltering) {
+ base::Time time = base::Time::Now();
+
+ // Run the loop twice. The first run has no files. The second run does.
+ for (int loop_count = 0; loop_count < 2; ++loop_count) {
+ if (loop_count == 1) {
+ PopulateDirectoryWithTestCases(root_path(),
+ kFilteringTestCases,
+ arraysize(kFilteringTestCases));
+ }
+ for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
+ FileSystemURL root_url = CreateURL(FPL(""));
+ FileSystemOperation* operation = NewOperation(root_url);
+
+ FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
+
+ std::string test_name = base::StringPrintf(
+ "TouchFileFiltering run %d test %" PRIuS, loop_count, i);
+ base::PlatformFileError expectation = base::PLATFORM_FILE_OK;
+ if (loop_count == 0 || !kFilteringTestCases[i].visible) {
+ // Files do not exists. Touch fails.
+ expectation = base::PLATFORM_FILE_ERROR_FAILED;
+ }
+ operation->TouchFile(
+ url, time, time, base::Bind(&ExpectEqHelper, test_name, expectation));
+ MessageLoop::current()->RunUntilIdle();
+ }
+ }
+}
+
+} // namespace chrome
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.cc b/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.cc
new file mode 100644
index 0000000..bdfea21
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.cc
@@ -0,0 +1,186 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
+
+#include <cstring>
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace picasaimport {
+
+namespace {
+
+const size_t kPmpMaxFilesize = 50*1024*1024; // Maximum of 50 MB.
+
+} // namespace
+
+PmpColumnReader::PmpColumnReader()
+ : length_(0),
+ field_type_(PMP_TYPE_INVALID),
+ rows_(0) { }
+
+PmpColumnReader::~PmpColumnReader() { }
+
+bool PmpColumnReader::Init(const base::FilePath& filepath, uint32* rows_read) {
+ DCHECK(!data_.get());
+ base::ThreadRestrictions::AssertIOAllowed();
+
+ int64 length = 0; // Signed temporary.
+ if (!file_util::GetFileSize(filepath, &length))
+ return false;
+
+ length_ = length;
+
+ if (length_ < kPmpHeaderSize || length_ > kPmpMaxFilesize)
+ return false;
+
+ data_.reset(new uint8[length_]);
+
+ char* data_begin = reinterpret_cast<char*>(data_.get());
+
+ return file_util::ReadFile(filepath, data_begin, length_) &&
+ ParseData(rows_read);
+}
+
+bool PmpColumnReader::ReadString(const uint32 row, std::string* result) const {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GT(length_, kPmpHeaderSize + row);
+
+ if (field_type_ != PMP_TYPE_STRING || row >= rows_)
+ return false;
+
+ *result = strings_[row];
+ return true;
+}
+
+bool PmpColumnReader::ReadUInt32(const uint32 row, uint32* result) const {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GT(length_, kPmpHeaderSize + row * sizeof(uint32));
+
+ if (field_type_ != PMP_TYPE_UINT32 || row >= rows_)
+ return false;
+
+ *result = reinterpret_cast<uint32*>(data_.get() + kPmpHeaderSize)[row];
+ return true;
+}
+
+bool PmpColumnReader::ReadDouble64(const uint32 row, double* result) const {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GT(length_, kPmpHeaderSize + row * sizeof(double));
+
+ if (field_type_ != PMP_TYPE_DOUBLE64 || row >= rows_)
+ return false;
+
+ *result = reinterpret_cast<double*>(data_.get() + kPmpHeaderSize)[row];
+ return true;
+}
+
+bool PmpColumnReader::ReadUInt8(const uint32 row, uint8* result) const {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GT(length_, kPmpHeaderSize + row * sizeof(uint8));
+
+ if (field_type_ != PMP_TYPE_UINT8 || row >= rows_)
+ return false;
+
+ *result = reinterpret_cast<uint8*>(data_.get() + kPmpHeaderSize)[row];
+ return true;
+}
+
+bool PmpColumnReader::ReadUInt64(const uint32 row, uint64* result) const {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GT(length_, kPmpHeaderSize + row * sizeof(uint64));
+
+ if (field_type_ != PMP_TYPE_UINT64 || row >= rows_)
+ return false;
+
+ *result = reinterpret_cast<uint64*>(data_.get() + kPmpHeaderSize)[row];
+ return true;
+}
+
+bool PmpColumnReader::ParseData(uint32* rows_read) {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GE(length_, kPmpHeaderSize);
+
+ // Check all magic bytes.
+ if (memcmp(&kPmpMagic1, &data_[kPmpMagic1Offset], sizeof(kPmpMagic1)) != 0 ||
+ memcmp(&kPmpMagic2, &data_[kPmpMagic2Offset], sizeof(kPmpMagic2)) != 0 ||
+ memcmp(&kPmpMagic3, &data_[kPmpMagic3Offset], sizeof(kPmpMagic3)) != 0 ||
+ memcmp(&kPmpMagic4, &data_[kPmpMagic4Offset], sizeof(kPmpMagic4)) != 0) {
+ return false;
+ }
+
+ uint16 field_type_data =
+ *(reinterpret_cast<uint16*>(&data_[kPmpFieldType1Offset]));
+
+ // Verify if field type matches second declaration
+ if (field_type_data !=
+ *(reinterpret_cast<uint16*>(&data_[kPmpFieldType2Offset]))) {
+ return false;
+ }
+
+ field_type_ = static_cast<PmpFieldType>(field_type_data);
+
+ rows_ = *(reinterpret_cast<uint32*>(&data_[kPmpRowCountOffset]));
+
+ size_t body_length = length_ - kPmpHeaderSize;
+ size_t expected_body_length = 0;
+ switch (field_type_) {
+ case PMP_TYPE_STRING:
+ expected_body_length = IndexStrings();
+ break;
+ case PMP_TYPE_UINT32:
+ expected_body_length = rows_ * sizeof(uint32);
+ break;
+ case PMP_TYPE_DOUBLE64:
+ expected_body_length = rows_ * sizeof(double);
+ break;
+ case PMP_TYPE_UINT8:
+ expected_body_length = rows_ * sizeof(uint8);
+ break;
+ case PMP_TYPE_UINT64:
+ expected_body_length = rows_ * sizeof(uint64);
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ if (body_length == expected_body_length && rows_read)
+ *rows_read = rows_;
+ return body_length == expected_body_length;
+}
+
+long PmpColumnReader::IndexStrings() {
+ DCHECK(data_.get() != NULL);
+ DCHECK_GE(length_, kPmpHeaderSize);
+
+ strings_.reserve(rows_);
+
+ size_t bytes_parsed = kPmpHeaderSize;
+ const uint8* data_cursor = data_.get() + kPmpHeaderSize;
+
+ while (strings_.size() < rows_) {
+ const uint8* string_end = static_cast<const uint8*>(
+ memchr(data_cursor, '\0', length_ - bytes_parsed));
+
+ // Fail if cannot find null termination. String runs on past file end.
+ if (string_end == NULL)
+ return -1;
+
+ // Length of string. (+1 to include the termination character).
+ ptrdiff_t length_in_bytes = string_end - data_cursor + 1;
+
+ strings_.push_back(reinterpret_cast<const char*>(data_cursor));
+ data_cursor += length_in_bytes;
+ bytes_parsed += length_in_bytes;
+ }
+
+ return bytes_parsed - kPmpHeaderSize;
+}
+
+} // namespace picasaimport
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h b/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h
new file mode 100644
index 0000000..280b91c
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h
@@ -0,0 +1,66 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_COLUMN_READER_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_COLUMN_READER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace picasaimport {
+
+// Reads a single PMP column from a file.
+class PmpColumnReader {
+ public:
+ PmpColumnReader();
+ virtual ~PmpColumnReader();
+
+ // Returns true if read successfully.
+ // |rows_read| is undefined if returns false.
+ bool Init(const base::FilePath& filepath, uint32* rows_read);
+
+ // These functions read the value of that |row| into |result|.
+ // Functions return false if the column is of the wrong type or the row
+ // is out of range.
+ bool ReadString(const uint32 row, std::string* result) const;
+ bool ReadUInt32(const uint32 row, uint32* result) const;
+ bool ReadDouble64(const uint32 row, double* result) const;
+ bool ReadUInt8(const uint32 row, uint8* result) const;
+ bool ReadUInt64(const uint32 row, uint64* result) const;
+
+ // Returns the native encoding of field_type.
+ PmpFieldType field_type() const {
+ return field_type_;
+ }
+
+ private:
+ bool ParseData(uint32* rows_read);
+ // Returns the number of bytes parsed in the body, or, -1 on failure.
+ long IndexStrings();
+
+ // Source data
+ scoped_ptr<uint8[]> data_;
+ size_t length_;
+
+ // Header data
+ PmpFieldType field_type_;
+ uint32 rows_;
+
+ // Index of string start locations if fields are strings. Empty otherwise.
+ std::vector<const char*> strings_;
+
+ DISALLOW_COPY_AND_ASSIGN(PmpColumnReader);
+};
+
+} // namespace picasaimport
+
+#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_COLUMN_READER_H_
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader_unittest.cc b/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader_unittest.cc
new file mode 100644
index 0000000..3646113
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader_unittest.cc
@@ -0,0 +1,179 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <algorithm>
+#include <vector>
+
+#include "base/file_util.h"
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using picasaimport::PmpColumnReader;
+using picasaimport::PmpTestHelper;
+
+// Overridden version of Read method to make test code templatable.
+bool DoRead(const PmpColumnReader* reader, uint32 row, std::string* target) {
+ return reader->ReadString(row, target);
+}
+
+bool DoRead(const PmpColumnReader* reader, uint32 row, uint32* target) {
+ return reader->ReadUInt32(row, target);
+}
+
+bool DoRead(const PmpColumnReader* reader, uint32 row, double* target) {
+ return reader->ReadDouble64(row, target);
+}
+
+bool DoRead(const PmpColumnReader* reader, uint32 row, uint8* target) {
+ return reader->ReadUInt8(row, target);
+}
+
+bool DoRead(const PmpColumnReader* reader, uint32 row, uint64* target) {
+ return reader->ReadUInt64(row, target);
+}
+
+// TestValid
+template<class T>
+void TestValid(const picasaimport::PmpFieldType field_type,
+ const std::vector<T>& elems) {
+ PmpTestHelper test_helper;
+ ASSERT_TRUE(test_helper.Init());
+
+ PmpColumnReader reader;
+
+ uint32 rows_read = 0xFF;
+
+ std::vector<uint8> data =
+ PmpTestHelper::MakeHeaderAndBody(field_type, elems.size(), elems);
+ ASSERT_TRUE(test_helper.InitColumnReaderFromBytes(&reader, data, &rows_read));
+ EXPECT_EQ(elems.size(), rows_read);
+
+ for (uint32 i = 0; i < elems.size() && i < rows_read; i++) {
+ T target;
+ EXPECT_TRUE(DoRead(&reader, i, &target));
+ EXPECT_EQ(elems[i], target);
+ }
+}
+
+template<class T>
+void TestMalformed(const picasaimport::PmpFieldType field_type,
+ const std::vector<T>& elems) {
+ PmpTestHelper test_helper;
+ ASSERT_TRUE(test_helper.Init());
+
+ PmpColumnReader reader1, reader2, reader3, reader4;
+
+ std::vector<uint8> data_too_few_declared_rows =
+ PmpTestHelper::MakeHeaderAndBody(field_type, elems.size()-1, elems);
+ EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
+ &reader1, data_too_few_declared_rows, NULL));
+
+ std::vector<uint8> data_too_many_declared_rows =
+ PmpTestHelper::MakeHeaderAndBody(field_type, elems.size()+1, elems);
+ EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
+ &reader2, data_too_many_declared_rows, NULL));
+
+ std::vector<uint8> data_truncated =
+ PmpTestHelper::MakeHeaderAndBody(field_type, elems.size(), elems);
+ data_truncated.resize(data_truncated.size()-10);
+ EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
+ &reader3, data_truncated, NULL));
+
+ std::vector<uint8> data_padded =
+ PmpTestHelper::MakeHeaderAndBody(field_type, elems.size(), elems);
+ data_padded.resize(data_padded.size()+10);
+ EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
+ &reader4, data_padded, NULL));
+}
+
+template<class T>
+void TestPrimitive(const picasaimport::PmpFieldType field_type) {
+ // Make an ascending vector of the primitive.
+ uint32 n = 100;
+ std::vector<T> data(n, 0);
+ for (uint32 i = 0; i < n; i++) {
+ data[i] = i*3;
+ }
+
+ TestValid<T>(field_type, data);
+ TestMalformed<T>(field_type, data);
+}
+
+
+TEST(PmpColumnReaderTest, HeaderParsingAndValidation) {
+ PmpTestHelper test_helper;
+ ASSERT_TRUE(test_helper.Init());
+
+ PmpColumnReader reader1, reader2, reader3, reader4, reader5;
+
+ // Good header.
+ uint32 rows_read = 0xFF;
+ std::vector<uint8> good_header = PmpTestHelper::MakeHeader(
+ picasaimport::PMP_TYPE_STRING, 0);
+ ASSERT_TRUE(test_helper.InitColumnReaderFromBytes(
+ &reader1, good_header, &rows_read));
+ EXPECT_EQ(0U, rows_read) << "Read non-zero rows from header-only data.";
+
+ // Botch up elements of the header.
+ std::vector<uint8> bad_magic_byte = PmpTestHelper::MakeHeader(
+ picasaimport::PMP_TYPE_STRING, 0);
+ bad_magic_byte[0] = 0xff;
+ EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
+ &reader2, bad_magic_byte, NULL));
+
+ // Corrupt means the type fields don't agree.
+ std::vector<uint8> corrupt_type = PmpTestHelper::MakeHeader(
+ picasaimport::PMP_TYPE_STRING, 0);
+ corrupt_type[picasaimport::kPmpFieldType1Offset] = 0xff;
+ EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
+ &reader3, corrupt_type, NULL));
+
+ std::vector<uint8> invalid_type = PmpTestHelper::MakeHeader(
+ picasaimport::PMP_TYPE_STRING, 0);
+ invalid_type[picasaimport::kPmpFieldType1Offset] = 0xff;
+ invalid_type[picasaimport::kPmpFieldType2Offset] = 0xff;
+ EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
+ &reader4, invalid_type, NULL));
+
+ std::vector<uint8> incomplete_header = PmpTestHelper::MakeHeader(
+ picasaimport::PMP_TYPE_STRING, 0);
+ incomplete_header.resize(10);
+ EXPECT_FALSE(test_helper.InitColumnReaderFromBytes(
+ &reader5, incomplete_header, NULL));
+}
+
+TEST(PmpColumnReaderTest, StringParsing) {
+ std::vector<std::string> empty_strings(100, "");
+
+ // Test empty strings read okay.
+ TestValid(picasaimport::PMP_TYPE_STRING, empty_strings);
+
+ std::vector<std::string> mixed_strings;
+ mixed_strings.push_back("");
+ mixed_strings.push_back("Hello");
+ mixed_strings.push_back("World");
+ mixed_strings.push_back("");
+ mixed_strings.push_back("123123");
+ mixed_strings.push_back("Q");
+ mixed_strings.push_back("");
+
+ // Test that a mixed set of strings read correctly.
+ TestValid(picasaimport::PMP_TYPE_STRING, mixed_strings);
+
+ // Test with the data messed up in a variety of ways.
+ TestMalformed(picasaimport::PMP_TYPE_STRING, mixed_strings);
+}
+
+TEST(PmpColumnReaderTest, PrimitiveParsing) {
+ TestPrimitive<uint32>(picasaimport::PMP_TYPE_UINT32);
+ TestPrimitive<double>(picasaimport::PMP_TYPE_DOUBLE64);
+ TestPrimitive<uint8>(picasaimport::PMP_TYPE_UINT8);
+ TestPrimitive<uint64>(picasaimport::PMP_TYPE_UINT64);
+}
+
+} // namespace
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h b/chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h
new file mode 100644
index 0000000..521c31a
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h
@@ -0,0 +1,46 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_CONSTANTS_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_CONSTANTS_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+namespace picasaimport {
+
+// PMP file format.
+// Info derived from: http://sbktech.blogspot.com/2011/12/picasa-pmp-format.html
+
+const char* const kPmpExtension = "pmp";
+
+const size_t kPmpHeaderSize = 20;
+
+const int kPmpMagic1Offset = 0;
+const int kPmpMagic2Offset = 6;
+const int kPmpMagic3Offset = 8;
+const int kPmpMagic4Offset = 14;
+
+const uint32 kPmpMagic1 = 0x3fcccccd;
+const uint16 kPmpMagic2 = 0x1332;
+const uint32 kPmpMagic3 = 0x00000002;
+const uint16 kPmpMagic4 = 0x1332;
+
+const int kPmpFieldType1Offset = 4;
+const int kPmpFieldType2Offset = 12;
+const int kPmpRowCountOffset = 16;
+
+enum PmpFieldType {
+ PMP_TYPE_STRING = 0x00,
+ PMP_TYPE_UINT32 = 0x01,
+ PMP_TYPE_DOUBLE64 = 0x02,
+ PMP_TYPE_UINT8 = 0x03,
+ PMP_TYPE_UINT64 = 0x04,
+ PMP_TYPE_INVALID = 0xff
+};
+
+} // namespace picasaimport
+
+#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_CONSTANTS_H_
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.cc b/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.cc
new file mode 100644
index 0000000..6a510b6
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.cc
@@ -0,0 +1,88 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h"
+
+#include <algorithm>
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
+
+namespace picasaimport {
+
+namespace {
+
+COMPILE_ASSERT(sizeof(double) == 8, double_must_be_8_bytes_long);
+
+} // namespace
+
+PmpTableReader::PmpTableReader() : column_readers_(), max_row_count_(0) { }
+
+PmpTableReader::~PmpTableReader() { }
+
+bool PmpTableReader::Init(const std::string& table_name,
+ const base::FilePath& directory_path,
+ const std::vector<std::string>& columns) {
+ DCHECK(!columns.empty());
+
+ if (!column_readers_.empty())
+ return false;
+
+ if (!file_util::DirectoryExists(directory_path))
+ return false;
+
+ std::string table_prefix = table_name + "_";
+ std::string indicator_file_name = table_prefix + "0";
+
+ base::FilePath indicator_file = directory_path.Append(
+ base::FilePath::FromUTF8Unsafe(indicator_file_name));
+
+ // Look for the indicator_file file, indicating table existence.
+ if (!file_util::PathExists(indicator_file) ||
+ file_util::DirectoryExists(indicator_file)) {
+ return false;
+ }
+
+ ScopedVector<PmpColumnReader> column_readers;
+ uint32 max_row_count = 0;
+
+ for (std::vector<std::string>::const_iterator it = columns.begin();
+ it != columns.end(); ++it) {
+ std::string filename = table_prefix + *it + "." + kPmpExtension;
+
+ base::FilePath column_file_path = directory_path.Append(
+ base::FilePath::FromUTF8Unsafe(filename));
+
+ PmpColumnReader* column_reader = new PmpColumnReader();
+ column_readers.push_back(column_reader);
+
+ uint32 row_cnt;
+
+ if (!column_reader->Init(column_file_path, &row_cnt))
+ return false;
+
+ max_row_count = std::max(max_row_count, row_cnt);
+ }
+
+ column_readers_ = column_readers.Pass();
+ max_row_count_ = max_row_count;
+
+ return true;
+}
+
+uint32 PmpTableReader::RowCount() const {
+ return max_row_count_;
+}
+
+std::vector<const PmpColumnReader*> PmpTableReader::GetColumns() const {
+ std::vector<const PmpColumnReader*> readers(
+ column_readers_.begin(), column_readers_.end());
+ return readers;
+}
+
+} // namespace picasaimport
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h b/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h
new file mode 100644
index 0000000..3cee4f7
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h
@@ -0,0 +1,47 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TABLE_READER_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TABLE_READER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_vector.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace picasaimport {
+
+class PmpColumnReader;
+
+class PmpTableReader {
+ public:
+ PmpTableReader();
+
+ virtual ~PmpTableReader();
+
+ // |columns| parameter will define, in-order, the columns returned by
+ // subsequent columns to GetColumns() if Init() succeeds.
+ bool Init(const std::string& table_name,
+ const base::FilePath& directory_path,
+ const std::vector<std::string>& columns);
+
+ // Returns a const "view" of the current contents of |column_readers_|.
+ std::vector<const PmpColumnReader*> GetColumns() const;
+
+ uint32 RowCount() const;
+
+ private:
+ ScopedVector<PmpColumnReader> column_readers_;
+ uint32 max_row_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(PmpTableReader);
+};
+
+} // namespace picasaimport
+
+#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TABLE_READER_H_
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader_unittest.cc b/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader_unittest.cc
new file mode 100644
index 0000000..dd6ece7
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader_unittest.cc
@@ -0,0 +1,72 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <algorithm>
+#include <vector>
+
+#include "base/file_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_table_reader.h"
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using picasaimport::PmpTestHelper;
+
+TEST(PmpTableReaderTest, RowCountAndFieldType) {
+ PmpTestHelper test_helper;
+ ASSERT_TRUE(test_helper.Init());
+
+ std::string table_name = "testtable";
+
+ std::vector<std::string> column_names;
+ column_names.push_back("strings");
+ column_names.push_back("uint32s");
+ column_names.push_back("doubles");
+
+ const std::vector<std::string> strings_vector(10, "Hello");
+ const std::vector<uint32> uint32s_vector(30, 42);
+ const std::vector<double> doubles_vector(20, 0.5);
+
+ picasaimport::PmpFieldType column_field_types[] = {
+ picasaimport::PMP_TYPE_STRING,
+ picasaimport::PMP_TYPE_UINT32,
+ picasaimport::PMP_TYPE_DOUBLE64
+ };
+
+ const uint32 max_rows = uint32s_vector.size();
+
+ base::FilePath indicator_path = test_helper.GetTempDirPath().Append(
+ base::FilePath::FromUTF8Unsafe(table_name + "_0"));
+
+ ASSERT_EQ(0, file_util::WriteFile(indicator_path, NULL, 0));
+ // Write three column files, one each for strings, uint32s, and doubles.
+
+ ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
+ table_name, column_names[0], column_field_types[0], strings_vector));
+
+ ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
+ table_name, column_names[1], column_field_types[1], uint32s_vector));
+
+ ASSERT_TRUE(test_helper.WriteColumnFileFromVector(
+ table_name, column_names[2], column_field_types[2], doubles_vector));
+
+ picasaimport::PmpTableReader table_reader;
+ ASSERT_TRUE(table_reader.Init(
+ table_name, test_helper.GetTempDirPath(), column_names));
+
+ EXPECT_EQ(max_rows, table_reader.RowCount());
+
+ const std::vector<const picasaimport::PmpColumnReader*> column_readers =
+ table_reader.GetColumns();
+
+ for (int i = 0; i < 3; i++) {
+ EXPECT_EQ(column_field_types[i], column_readers[i]->field_type());
+ }
+}
+
+} // namespace
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.cc b/chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.cc
new file mode 100644
index 0000000..f426d96
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.cc
@@ -0,0 +1,172 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_column_reader.h"
+
+namespace picasaimport {
+
+namespace {
+
+bool WriteToFile(const base::FilePath& path, std::vector<uint8> data) {
+ // Cast for usage in WriteFile function
+ const char* data_char = reinterpret_cast<const char*>(&data[0]);
+ size_t bytes_written = file_util::WriteFile(path, data_char, data.size());
+ return (bytes_written == data.size());
+}
+
+// Flatten a vector of elements into an array of bytes.
+template<class T>
+std::vector<uint8> Flatten(const std::vector<T>& elems) {
+ const uint8* elems0 = reinterpret_cast<const uint8*>(&elems[0]);
+ std::vector<uint8> data_body(elems0, elems0 + sizeof(T)*elems.size());
+
+ return data_body;
+}
+
+// Custom specialization for std::string.
+template<>
+std::vector<uint8> Flatten(const std::vector<std::string>& strings) {
+ std::vector<uint8> totalchars;
+
+ for (std::vector<std::string>::const_iterator it = strings.begin();
+ it != strings.end(); ++it) {
+ std::copy(it->begin(), it->end(), std::back_inserter(totalchars));
+ totalchars.push_back('\0'); // Add the null termination too.
+ }
+
+ return totalchars;
+}
+
+// Returns a new vector with the concatenated contents of |a| and |b|.
+std::vector<uint8> CombinedVectors(const std::vector<uint8>& a,
+ const std::vector<uint8>& b) {
+ std::vector<uint8> total;
+
+ std::copy(a.begin(), a.end(), std::back_inserter(total));
+ std::copy(b.begin(), b.end(), std::back_inserter(total));
+
+ return total;
+}
+
+} // namespace
+
+PmpTestHelper::PmpTestHelper() { }
+
+bool PmpTestHelper::Init() {
+ return temp_dir_.CreateUniqueTempDir();
+}
+
+base::FilePath PmpTestHelper::GetTempDirPath() {
+ DCHECK(temp_dir_.IsValid());
+ return temp_dir_.path();
+}
+
+template<class T>
+bool PmpTestHelper::WriteColumnFileFromVector(
+ const std::string& table_name, const std::string& column_name,
+ const PmpFieldType field_type, const std::vector<T>& elements_vector) {
+ DCHECK(temp_dir_.IsValid());
+
+ std::string file_name = table_name + "_" + column_name + "." + kPmpExtension;
+
+ base::FilePath path = temp_dir_.path().Append(
+ base::FilePath::FromUTF8Unsafe(file_name));
+
+ std::vector<uint8> data = PmpTestHelper::MakeHeaderAndBody(
+ field_type, elements_vector.size(), elements_vector);
+
+ return WriteToFile(path, data);
+}
+
+// Explicit Instantiation for all the valid types.
+template bool PmpTestHelper::WriteColumnFileFromVector<std::string>(
+ const std::string&, const std::string&, const PmpFieldType,
+ const std::vector<std::string>&);
+template bool PmpTestHelper::WriteColumnFileFromVector<uint32>(
+ const std::string&, const std::string&, const PmpFieldType,
+ const std::vector<uint32>&);
+template bool PmpTestHelper::WriteColumnFileFromVector<double>(
+ const std::string&, const std::string&, const PmpFieldType,
+ const std::vector<double>&);
+template bool PmpTestHelper::WriteColumnFileFromVector<uint8>(
+ const std::string&, const std::string&, const PmpFieldType,
+ const std::vector<uint8>&);
+template bool PmpTestHelper::WriteColumnFileFromVector<uint64>(
+ const std::string&, const std::string&, const PmpFieldType,
+ const std::vector<uint64>&);
+
+bool PmpTestHelper::InitColumnReaderFromBytes(
+ PmpColumnReader* const reader, const std::vector<uint8>& data,
+ uint32* rows_read) {
+ DCHECK(temp_dir_.IsValid());
+
+ base::FilePath temp_path;
+
+ if (!file_util::CreateTemporaryFileInDir(temp_dir_.path(), &temp_path) ||
+ !WriteToFile(temp_path, data)) {
+ return false;
+ }
+
+ bool success = reader->Init(temp_path, rows_read);
+
+ file_util::Delete(temp_path, true);
+
+ return success;
+
+}
+
+// Return a vector so we don't have to worry about memory management.
+std::vector<uint8> PmpTestHelper::MakeHeader(const PmpFieldType field_type,
+ const uint32 row_count) {
+ std::vector<uint8> header(picasaimport::kPmpHeaderSize);
+
+ // Copy in magic bytes.
+ memcpy(&header[picasaimport::kPmpMagic1Offset], &picasaimport::kPmpMagic1,
+ sizeof(picasaimport::kPmpMagic1));
+ memcpy(&header[picasaimport::kPmpMagic2Offset], &picasaimport::kPmpMagic2,
+ sizeof(picasaimport::kPmpMagic2));
+ memcpy(&header[picasaimport::kPmpMagic3Offset], &picasaimport::kPmpMagic3,
+ sizeof(picasaimport::kPmpMagic3));
+ memcpy(&header[picasaimport::kPmpMagic4Offset], &picasaimport::kPmpMagic4,
+ sizeof(picasaimport::kPmpMagic4));
+
+ // Copy in field type.
+ memcpy(&header[picasaimport::kPmpFieldType1Offset], &field_type, 2);
+ memcpy(&header[picasaimport::kPmpFieldType2Offset], &field_type, 2);
+
+ // Copy in row count.
+ memcpy(&header[picasaimport::kPmpRowCountOffset], &row_count, 4);
+
+ return header;
+}
+
+template<class T>
+std::vector<uint8> PmpTestHelper::MakeHeaderAndBody(
+ const PmpFieldType field_type, const uint32 row_count,
+ const std::vector<T>& elems) {
+ return CombinedVectors(PmpTestHelper::MakeHeader(field_type, row_count),
+ Flatten(elems));
+}
+
+// Explicit Instantiation for all the valid types.
+template std::vector<uint8> PmpTestHelper::MakeHeaderAndBody<std::string>(
+ const PmpFieldType, const uint32, const std::vector<std::string>&);
+template std::vector<uint8> PmpTestHelper::MakeHeaderAndBody<uint32>(
+ const PmpFieldType, const uint32, const std::vector<uint32>&);
+template std::vector<uint8> PmpTestHelper::MakeHeaderAndBody<double>(
+ const PmpFieldType, const uint32, const std::vector<double>&);
+template std::vector<uint8> PmpTestHelper::MakeHeaderAndBody<uint8>(
+ const PmpFieldType, const uint32, const std::vector<uint8>&);
+template std::vector<uint8> PmpTestHelper::MakeHeaderAndBody<uint64>(
+ const PmpFieldType, const uint32, const std::vector<uint64>&);
+
+} // namespace picasaimport
diff --git a/chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h b/chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h
new file mode 100644
index 0000000..d675773
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/picasa/pmp_test_helper.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TEST_HELPER_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TEST_HELPER_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/files/scoped_temp_dir.h"
+#include "chrome/browser/media_galleries/fileapi/picasa/pmp_constants.h"
+
+namespace base {
+class FilePath;
+} // namespace base
+
+namespace picasaimport {
+
+class PmpColumnReader;
+
+// A helper class used for unit tests only
+class PmpTestHelper {
+ public:
+ PmpTestHelper();
+
+ bool Init();
+
+ base::FilePath GetTempDirPath();
+
+ template<class T>
+ bool WriteColumnFileFromVector(const std::string& table_name,
+ const std::string& column_name,
+ const PmpFieldType field_type,
+ const std::vector<T>& elements_vector);
+
+ bool InitColumnReaderFromBytes(PmpColumnReader* const reader,
+ const std::vector<uint8>& data,
+ uint32* rows_read);
+
+ static std::vector<uint8> MakeHeader(const PmpFieldType field_type,
+ const uint32 row_count);
+
+ template<class T>
+ static std::vector<uint8> MakeHeaderAndBody(const PmpFieldType field_type,
+ const uint32 row_count,
+ const std::vector<T>& elems);
+
+ private:
+ base::ScopedTempDir temp_dir_;
+};
+
+} // namespace picasaimport
+
+#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_PICASA_PMP_TEST_HELPER_H_
diff --git a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
index 01bc9d1..7483b17 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
+++ b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
@@ -12,9 +12,9 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/platform_file.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
#include "chrome/browser/media_galleries/mtp_device_delegate_impl.h"
#include "webkit/fileapi/async_file_util.h"
-#include "webkit/fileapi/media/mtp_device_async_delegate.h"
namespace base {
class FilePath;
@@ -30,7 +30,7 @@ struct SnapshotRequestInfo;
// MTPDeviceDelegateImplLinux lives on the IO thread.
// MTPDeviceDelegateImplLinux does a call-and-reply to the UI thread
// to dispatch the requests to MediaTransferProtocolManager.
-class MTPDeviceDelegateImplLinux : public fileapi::MTPDeviceAsyncDelegate {
+class MTPDeviceDelegateImplLinux : public MTPDeviceAsyncDelegate {
private:
friend void CreateMTPDeviceAsyncDelegate(
const std::string&,
diff --git a/chrome/browser/media_galleries/linux/mtp_device_task_helper.h b/chrome/browser/media_galleries/linux/mtp_device_task_helper.h
index d817212..f1389fe 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_task_helper.h
+++ b/chrome/browser/media_galleries/linux/mtp_device_task_helper.h
@@ -12,9 +12,9 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/platform_file.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
#include "device/media_transfer_protocol/mtp_file_entry.pb.h"
#include "webkit/fileapi/async_file_util.h"
-#include "webkit/fileapi/media/mtp_device_async_delegate.h"
namespace chrome {
@@ -31,13 +31,13 @@ class MTPDeviceTaskHelper {
public:
typedef base::Callback<void(bool succeeded)> OpenStorageCallback;
- typedef fileapi::MTPDeviceAsyncDelegate::GetFileInfoSuccessCallback
+ typedef MTPDeviceAsyncDelegate::GetFileInfoSuccessCallback
GetFileInfoSuccessCallback;
typedef base::Callback<void(const fileapi::AsyncFileUtil::EntryList&)>
ReadDirectorySuccessCallback;
- typedef fileapi::MTPDeviceAsyncDelegate::ErrorCallback ErrorCallback;
+ typedef MTPDeviceAsyncDelegate::ErrorCallback ErrorCallback;
MTPDeviceTaskHelper();
~MTPDeviceTaskHelper();
diff --git a/chrome/browser/media_galleries/linux/snapshot_file_details.cc b/chrome/browser/media_galleries/linux/snapshot_file_details.cc
index 2d85ccb..8f2e709 100644
--- a/chrome/browser/media_galleries/linux/snapshot_file_details.cc
+++ b/chrome/browser/media_galleries/linux/snapshot_file_details.cc
@@ -15,9 +15,9 @@ namespace chrome {
SnapshotRequestInfo::SnapshotRequestInfo(
const std::string& device_file_path,
const base::FilePath& snapshot_file_path,
- const fileapi::MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback&
+ const MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback&
success_callback,
- const fileapi::MTPDeviceAsyncDelegate::ErrorCallback& error_callback)
+ const MTPDeviceAsyncDelegate::ErrorCallback& error_callback)
: device_file_path(device_file_path),
snapshot_file_path(snapshot_file_path),
success_callback(success_callback),
diff --git a/chrome/browser/media_galleries/linux/snapshot_file_details.h b/chrome/browser/media_galleries/linux/snapshot_file_details.h
index c2157fc..e358b39 100644
--- a/chrome/browser/media_galleries/linux/snapshot_file_details.h
+++ b/chrome/browser/media_galleries/linux/snapshot_file_details.h
@@ -11,7 +11,7 @@
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/platform_file.h"
-#include "webkit/fileapi/media/mtp_device_async_delegate.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
namespace chrome {
@@ -20,9 +20,9 @@ struct SnapshotRequestInfo {
SnapshotRequestInfo(
const std::string& device_file_path,
const base::FilePath& snapshot_file_path,
- const fileapi::MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback&
+ const MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback&
success_callback,
- const fileapi::MTPDeviceAsyncDelegate::ErrorCallback& error_callback);
+ const MTPDeviceAsyncDelegate::ErrorCallback& error_callback);
~SnapshotRequestInfo();
// MTP device file path.
@@ -32,11 +32,11 @@ struct SnapshotRequestInfo {
const base::FilePath snapshot_file_path;
// A callback to be called when CreateSnapshotFile() succeeds.
- const fileapi::MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback
+ const MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback
success_callback;
// A callback to be called when CreateSnapshotFile() fails.
- const fileapi::MTPDeviceAsyncDelegate::ErrorCallback error_callback;
+ const MTPDeviceAsyncDelegate::ErrorCallback error_callback;
};
// SnapshotFileDetails tracks the current state of the snapshot file (e.g how
@@ -65,12 +65,12 @@ class SnapshotFileDetails {
return file_info_;
}
- const fileapi::MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback
+ const MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback
success_callback() const {
return request_info_.success_callback;
}
- const fileapi::MTPDeviceAsyncDelegate::ErrorCallback error_callback() const {
+ const MTPDeviceAsyncDelegate::ErrorCallback error_callback() const {
return request_info_.error_callback;
}
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h
index 201b314..bc3ac6f 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h
@@ -13,7 +13,7 @@
#include "base/hash_tables.h"
#include "base/memory/weak_ptr.h"
#include "base/platform_file.h"
-#include "webkit/fileapi/media/mtp_device_async_delegate.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
namespace chrome {
@@ -26,7 +26,7 @@ namespace chrome {
// on any thread, but then mutates all state on the UI thread. The async
// delegate interface can be invoked on any thread, as it simply forwards calls
// to the UI thread.
-class MTPDeviceDelegateImplMac : public fileapi::MTPDeviceAsyncDelegate {
+class MTPDeviceDelegateImplMac : public MTPDeviceAsyncDelegate {
public:
MTPDeviceDelegateImplMac(const std::string& device_id,
const base::FilePath::StringType& synthetic_path);
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
index 5f9a719..4a1de47 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
@@ -19,7 +19,6 @@ namespace {
int kReadDirectoryTimeLimitSeconds = 20;
-using fileapi::MTPDeviceAsyncDelegate;
typedef MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback
CreateSnapshotFileSuccessCallback;
typedef MTPDeviceAsyncDelegate::ErrorCallback ErrorCallback;
diff --git a/chrome/browser/media_galleries/media_file_system_context.h b/chrome/browser/media_galleries/media_file_system_context.h
index ccc0371..eebcd2d 100644
--- a/chrome/browser/media_galleries/media_file_system_context.h
+++ b/chrome/browser/media_galleries/media_file_system_context.h
@@ -10,8 +10,8 @@
#include <string>
#include "base/memory/ref_counted.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_file_system_config.h"
#include "chrome/browser/media_galleries/scoped_mtp_device_map_entry.h"
-#include "webkit/fileapi/media/mtp_device_file_system_config.h"
namespace base {
class FilePath;
diff --git a/chrome/browser/media_galleries/media_file_system_registry.h b/chrome/browser/media_galleries/media_file_system_registry.h
index 7ce269a..6843c3a 100644
--- a/chrome/browser/media_galleries/media_file_system_registry.h
+++ b/chrome/browser/media_galleries/media_file_system_registry.h
@@ -17,9 +17,9 @@
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/prefs/pref_change_registrar.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_file_system_config.h"
#include "chrome/browser/media_galleries/media_galleries_preferences.h"
#include "chrome/browser/storage_monitor/removable_storage_observer.h"
-#include "webkit/fileapi/media/mtp_device_file_system_config.h"
#if defined(SUPPORT_MTP_DEVICE_FILESYSTEM)
#include "chrome/browser/media_galleries/mtp_device_delegate_impl.h"
diff --git a/chrome/browser/media_galleries/mtp_device_delegate_impl.h b/chrome/browser/media_galleries/mtp_device_delegate_impl.h
index 632c024..3490c6e 100644
--- a/chrome/browser/media_galleries/mtp_device_delegate_impl.h
+++ b/chrome/browser/media_galleries/mtp_device_delegate_impl.h
@@ -5,7 +5,7 @@
#ifndef CHROME_BROWSER_MEDIA_GALLERIES_MTP_DEVICE_DELEGATE_IMPL_H_
#define CHROME_BROWSER_MEDIA_GALLERIES_MTP_DEVICE_DELEGATE_IMPL_H_
-#include "webkit/fileapi/media/mtp_device_file_system_config.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_file_system_config.h"
#if !defined(SUPPORT_MTP_DEVICE_FILESYSTEM)
#error "Media file system is not supported for this platform."
@@ -13,7 +13,7 @@
#include "base/callback_forward.h"
#include "base/files/file_path.h"
-#include "webkit/fileapi/media/mtp_device_async_delegate.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
namespace base {
class SequencedTaskRunner;
@@ -21,7 +21,7 @@ class SequencedTaskRunner;
namespace chrome {
-typedef base::Callback<void(fileapi::MTPDeviceAsyncDelegate*)>
+typedef base::Callback<void(MTPDeviceAsyncDelegate*)>
CreateMTPDeviceAsyncDelegateCallback;
void CreateMTPDeviceAsyncDelegate(
diff --git a/chrome/browser/media_galleries/scoped_mtp_device_map_entry.cc b/chrome/browser/media_galleries/scoped_mtp_device_map_entry.cc
index b91d641..2444f0a 100644
--- a/chrome/browser/media_galleries/scoped_mtp_device_map_entry.cc
+++ b/chrome/browser/media_galleries/scoped_mtp_device_map_entry.cc
@@ -4,15 +4,16 @@
#include "chrome/browser/media_galleries/scoped_mtp_device_map_entry.h"
-#include "webkit/fileapi/media/mtp_device_file_system_config.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_file_system_config.h"
#if defined(SUPPORT_MTP_DEVICE_FILESYSTEM)
#include "base/bind.h"
#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h"
#include "chrome/browser/media_galleries/mtp_device_delegate_impl.h"
#include "content/public/browser/browser_thread.h"
#include "webkit/fileapi/file_system_task_runners.h"
-#include "webkit/fileapi/media/mtp_device_map_service.h"
+
#endif
namespace chrome {
@@ -37,7 +38,7 @@ scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() {
void OnDeviceAsyncDelegateDestroyed(
const base::FilePath::StringType& device_location) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- fileapi::MTPDeviceMapService::GetInstance()->RemoveAsyncDelegate(
+ MTPDeviceMapService::GetInstance()->RemoveAsyncDelegate(
device_location);
}
@@ -82,10 +83,10 @@ ScopedMTPDeviceMapEntry::~ScopedMTPDeviceMapEntry() {
}
void ScopedMTPDeviceMapEntry::OnMTPDeviceAsyncDelegateCreated(
- fileapi::MTPDeviceAsyncDelegate* delegate) {
+ MTPDeviceAsyncDelegate* delegate) {
#if defined(SUPPORT_MTP_DEVICE_FILESYSTEM)
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- fileapi::MTPDeviceMapService::GetInstance()->AddAsyncDelegate(
+ MTPDeviceMapService::GetInstance()->AddAsyncDelegate(
device_location_, delegate);
#endif
}
diff --git a/chrome/browser/media_galleries/scoped_mtp_device_map_entry.h b/chrome/browser/media_galleries/scoped_mtp_device_map_entry.h
index 8cf24a2..abcf042 100644
--- a/chrome/browser/media_galleries/scoped_mtp_device_map_entry.h
+++ b/chrome/browser/media_galleries/scoped_mtp_device_map_entry.h
@@ -15,12 +15,10 @@
#include "base/sequenced_task_runner_helpers.h"
#include "content/public/browser/browser_thread.h"
-namespace fileapi {
-class MTPDeviceAsyncDelegate;
-}
-
namespace chrome {
+class MTPDeviceAsyncDelegate;
+
class ScopedMTPDeviceMapEntry
: public base::RefCountedThreadSafe<
ScopedMTPDeviceMapEntry, content::BrowserThread::DeleteOnUIThread> {
@@ -50,8 +48,7 @@ class ScopedMTPDeviceMapEntry
// Callback to add the managed MTPDeviceAsyncDelegate to the
// MTPDeviceMapService on the IO thread.
- void OnMTPDeviceAsyncDelegateCreated(
- fileapi::MTPDeviceAsyncDelegate* delegate);
+ void OnMTPDeviceAsyncDelegateCreated(MTPDeviceAsyncDelegate* delegate);
// The MTP or PTP device location.
const base::FilePath::StringType device_location_;
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h
index cdd6bdf..afae427 100644
--- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h
+++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h
@@ -14,9 +14,9 @@
#include "base/platform_file.h"
#include "base/string16.h"
#include "base/win/scoped_comptr.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
#include "chrome/browser/media_galleries/mtp_device_delegate_impl.h"
#include "webkit/fileapi/async_file_util.h"
-#include "webkit/fileapi/media/mtp_device_async_delegate.h"
namespace base {
class FilePath;
@@ -36,7 +36,7 @@ struct SnapshotRequestInfo;
// is instantiated per MTP device storage partition using
// CreateMTPDeviceAsyncDelegate(). MTPDeviceDelegateImplWin lives on the IO
// thread.
-class MTPDeviceDelegateImplWin : public fileapi::MTPDeviceAsyncDelegate {
+class MTPDeviceDelegateImplWin : public MTPDeviceAsyncDelegate {
public:
// Structure used to represent MTP device storage partition details.
struct StorageDeviceInfo {
diff --git a/chrome/browser/media_galleries/win/snapshot_file_details.cc b/chrome/browser/media_galleries/win/snapshot_file_details.cc
index 6b69418..073c97d 100644
--- a/chrome/browser/media_galleries/win/snapshot_file_details.cc
+++ b/chrome/browser/media_galleries/win/snapshot_file_details.cc
@@ -8,8 +8,6 @@
namespace chrome {
-using fileapi::MTPDeviceAsyncDelegate;
-
///////////////////////////////////////////////////////////////////////////////
// SnapshotRequestInfo //
///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/media_galleries/win/snapshot_file_details.h b/chrome/browser/media_galleries/win/snapshot_file_details.h
index d6f00ea..7c39ea3 100644
--- a/chrome/browser/media_galleries/win/snapshot_file_details.h
+++ b/chrome/browser/media_galleries/win/snapshot_file_details.h
@@ -8,7 +8,7 @@
#include "base/files/file_path.h"
#include "base/platform_file.h"
#include "base/win/scoped_comptr.h"
-#include "webkit/fileapi/media/mtp_device_async_delegate.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
namespace chrome {
@@ -17,9 +17,9 @@ struct SnapshotRequestInfo {
SnapshotRequestInfo(
const base::FilePath& device_file_path,
const base::FilePath& snapshot_file_path,
- const fileapi::MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback&
+ const MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback&
success_callback,
- const fileapi::MTPDeviceAsyncDelegate::ErrorCallback& error_callback);
+ const MTPDeviceAsyncDelegate::ErrorCallback& error_callback);
// Device file path.
base::FilePath device_file_path;
@@ -28,11 +28,11 @@ struct SnapshotRequestInfo {
base::FilePath snapshot_file_path;
// A callback to be called when CreateSnapshotFile() succeeds.
- fileapi::MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback
+ MTPDeviceAsyncDelegate::CreateSnapshotFileSuccessCallback
success_callback;
// A callback to be called when CreateSnapshotFile() fails.
- fileapi::MTPDeviceAsyncDelegate::ErrorCallback error_callback;
+ MTPDeviceAsyncDelegate::ErrorCallback error_callback;
};
// Provides the details for the the creation of snapshot file.