summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryawano <yawano@chromium.org>2015-03-04 19:43:15 -0800
committerCommit bot <commit-bot@chromium.org>2015-03-05 03:43:43 +0000
commit8cd28e349ab9605da7dbf97c8c85f8c541b3b59b (patch)
tree65bc75420d1f52d538c723bd0caf274ee44022a8
parent4f2eab7cd613d87c79a192bfc5183f79483d95bf (diff)
downloadchromium_src-8cd28e349ab9605da7dbf97c8c85f8c541b3b59b.zip
chromium_src-8cd28e349ab9605da7dbf97c8c85f8c541b3b59b.tar.gz
chromium_src-8cd28e349ab9605da7dbf97c8c85f8c541b3b59b.tar.bz2
Implement CopyFileFromLocal of MTPDeviceAsyncDelegate.
CopyFileFromLocal is a method to copy a local file to the device. This method will be used in CopyInForeingFile of AsyncFileUtil. A CL to connect CopyFileFromLocal to CopyInForeingFile will come later when all other write operations (e.g. delete) are implemented. BUG=413541 TEST=none; manually tested with changing write_supported variable in volume_manager.cc to true. Review URL: https://codereview.chromium.org/947943002 Cr-Commit-Position: refs/heads/master@{#319205}
-rw-r--r--chrome/browser/chromeos/file_manager/volume_manager.cc15
-rw-r--r--chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc33
-rw-r--r--chrome/browser/media_galleries/fileapi/device_media_async_file_util.h4
-rw-r--r--chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h14
-rw-r--r--chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc94
-rw-r--r--chrome/browser/media_galleries/fileapi/mtp_device_map_service.h31
-rw-r--r--chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc209
-rw-r--r--chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h28
-rw-r--r--chrome/browser/media_galleries/linux/mtp_device_task_helper.cc42
-rw-r--r--chrome/browser/media_galleries/linux/mtp_device_task_helper.h19
-rw-r--r--chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.cc32
-rw-r--r--chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.h21
-rw-r--r--chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h6
-rw-r--r--chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm16
-rw-r--r--chrome/browser/media_galleries/media_file_system_registry.cc9
-rw-r--r--chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc17
-rw-r--r--chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h6
-rw-r--r--components/storage_monitor/test_media_transfer_protocol_manager_linux.cc9
-rw-r--r--components/storage_monitor/test_media_transfer_protocol_manager_linux.h5
-rw-r--r--device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc37
-rw-r--r--device/media_transfer_protocol/media_transfer_protocol_daemon_client.h15
-rw-r--r--device/media_transfer_protocol/media_transfer_protocol_manager.cc33
-rw-r--r--device/media_transfer_protocol/media_transfer_protocol_manager.h12
23 files changed, 622 insertions, 85 deletions
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc
index 7c2dde6..6820aab 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -661,18 +661,23 @@ void VolumeManager::OnRemovableStorageAttached(
storage::FileSystemMountOption(),
path);
DCHECK(result);
+
+ // TODO(yawano) A variable to switch MTP write support. This variable should
+ // be false until MTP write operation is implemented and shipped.
+ bool write_supported = false;
+
content::BrowserThread::PostTask(
- content::BrowserThread::IO, FROM_HERE, base::Bind(
- &MTPDeviceMapService::RegisterMTPFileSystem,
- base::Unretained(MTPDeviceMapService::GetInstance()),
- info.location(), fsid));
+ content::BrowserThread::IO, FROM_HERE,
+ base::Bind(&MTPDeviceMapService::RegisterMTPFileSystem,
+ base::Unretained(MTPDeviceMapService::GetInstance()),
+ info.location(), fsid, !write_supported /* read_only */));
VolumeInfo volume_info;
volume_info.type = VOLUME_TYPE_MTP;
volume_info.mount_path = path;
volume_info.mount_condition = chromeos::disks::MOUNT_CONDITION_NONE;
volume_info.is_parent = true;
- volume_info.is_read_only = true;
+ volume_info.is_read_only = !write_supported;
volume_info.volume_id = kMtpVolumeIdPrefix + label;
volume_info.volume_label = label;
volume_info.source_path = path;
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
index 2245ba6..c106f65 100644
--- a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
@@ -79,6 +79,13 @@ void OnReadDirectoryError(const AsyncFileUtil::ReadDirectoryCallback& callback,
callback.Run(error, AsyncFileUtil::EntryList(), false /*no more*/);
}
+// Called when CopyInForeignFile method call failed.
+void OnCopyInForeignFileError(const AsyncFileUtil::StatusCallback& callback,
+ base::File::Error error) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ callback.Run(error);
+}
+
// 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 the
// "profile_path/kDeviceMediaAsyncFileUtilTempDir" directory. Return the
@@ -330,6 +337,7 @@ void DeviceMediaAsyncFileUtil::ReadDirectory(
OnReadDirectoryError(callback, base::File::FILE_ERROR_NOT_FOUND);
return;
}
+
delegate->ReadDirectory(
url.path(),
base::Bind(&DeviceMediaAsyncFileUtil::OnDidReadDirectory,
@@ -389,8 +397,22 @@ void DeviceMediaAsyncFileUtil::CopyInForeignFile(
const FileSystemURL& dest_url,
const StatusCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- NOTIMPLEMENTED();
- callback.Run(base::File::FILE_ERROR_SECURITY);
+
+ MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(dest_url);
+ if (!delegate) {
+ OnCopyInForeignFileError(callback, base::File::FILE_ERROR_NOT_FOUND);
+ return;
+ }
+ if (delegate->IsReadOnly()) {
+ OnCopyInForeignFileError(callback, base::File::FILE_ERROR_SECURITY);
+ return;
+ }
+
+ delegate->CopyFileFromLocal(
+ src_file_path, dest_url.path(),
+ base::Bind(&DeviceMediaAsyncFileUtil::OnDidCopyInForeignFile,
+ weak_ptr_factory_.GetWeakPtr(), callback),
+ base::Bind(&OnCopyInForeignFileError, callback));
}
void DeviceMediaAsyncFileUtil::DeleteFile(
@@ -511,6 +533,13 @@ void DeviceMediaAsyncFileUtil::OnDidReadDirectory(
base::Bind(&OnDidCheckMediaForReadDirectory, callback, has_more));
}
+void DeviceMediaAsyncFileUtil::OnDidCopyInForeignFile(
+ const StatusCallback& callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ callback.Run(base::File::FILE_OK);
+}
+
bool DeviceMediaAsyncFileUtil::validate_media_files() const {
return media_path_filter_wrapper_.get() != NULL;
}
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
index 3716c44..96c6b1d 100644
--- a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h
+++ b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h
@@ -141,6 +141,10 @@ class DeviceMediaAsyncFileUtil : public storage::AsyncFileUtil {
const EntryList& file_list,
bool has_more);
+ // Called when CopyInForeignFile method call succeeds. |callback| is invoked
+ // to complete the CopyInForeignFile request.
+ void OnDidCopyInForeignFile(const StatusCallback& callback);
+
bool validate_media_files() const;
// Profile path.
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
index f73c3f7..79555a3 100644
--- a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
+++ b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
@@ -63,6 +63,9 @@ class MTPDeviceAsyncDelegate {
ErrorCallback error_callback;
};
+ // A callback to be called when CopyFileFromLocal method call succeeds.
+ typedef base::Closure CopyFileFromLocalSuccessCallback;
+
// Gets information about the given |file_path| and invokes the appropriate
// callback asynchronously when complete.
virtual void GetFileInfo(
@@ -99,6 +102,16 @@ class MTPDeviceAsyncDelegate {
const ReadBytesSuccessCallback& success_callback,
const ErrorCallback& error_callback) = 0;
+ // Returns true if storage is opened for read only.
+ virtual bool IsReadOnly() = 0;
+
+ // Copies a file from |source_file_path| to |device_file_path|.
+ virtual void CopyFileFromLocal(
+ const base::FilePath& source_file_path,
+ const base::FilePath& device_file_path,
+ const CopyFileFromLocalSuccessCallback& 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)
@@ -119,6 +132,7 @@ typedef base::Callback<void(MTPDeviceAsyncDelegate*)>
void CreateMTPDeviceAsyncDelegate(
const base::FilePath::StringType& device_location,
+ const bool read_only,
const CreateMTPDeviceAsyncDelegateCallback& callback);
#endif // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_MTP_DEVICE_ASYNC_DELEGATE_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
index b85a9bb..6941878 100644
--- a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc
+++ b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.cc
@@ -26,64 +26,101 @@ MTPDeviceMapService* MTPDeviceMapService::GetInstance() {
void MTPDeviceMapService::RegisterMTPFileSystem(
const base::FilePath::StringType& device_location,
- const std::string& fsid) {
+ const std::string& filesystem_id,
+ const bool read_only) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ DCHECK(!device_location.empty());
+ DCHECK(!filesystem_id.empty());
- if (!ContainsKey(mtp_device_usage_map_, device_location)) {
+ const AsyncDelegateKey key = GetAsyncDelegateKey(device_location, read_only);
+ if (!ContainsKey(mtp_device_usage_map_, key)) {
// Note that this initializes the delegate asynchronously, but since
// the delegate will only be used from the IO thread, it is guaranteed
// to be created before use of it expects it to be there.
- CreateMTPDeviceAsyncDelegate(device_location,
+ CreateMTPDeviceAsyncDelegate(
+ device_location, read_only,
base::Bind(&MTPDeviceMapService::AddAsyncDelegate,
- base::Unretained(this), device_location));
- mtp_device_usage_map_[device_location] = 0;
+ base::Unretained(this), device_location, read_only));
+ mtp_device_usage_map_[key] = 0;
}
- mtp_device_usage_map_[device_location]++;
- mtp_device_map_[fsid] = device_location;
+ mtp_device_usage_map_[key]++;
+ mtp_device_map_[filesystem_id] = make_pair(device_location, read_only);
}
-void MTPDeviceMapService::RevokeMTPFileSystem(const std::string& fsid) {
+void MTPDeviceMapService::RevokeMTPFileSystem(
+ const std::string& filesystem_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ DCHECK(!filesystem_id.empty());
- MTPDeviceFileSystemMap::iterator it = mtp_device_map_.find(fsid);
+ MTPDeviceFileSystemMap::iterator it = mtp_device_map_.find(filesystem_id);
if (it != mtp_device_map_.end()) {
- base::FilePath::StringType device_location = it->second;
+ const base::FilePath::StringType device_location = it->second.first;
+ const bool read_only = it->second.second;
+
mtp_device_map_.erase(it);
- MTPDeviceUsageMap::iterator delegate_it =
- mtp_device_usage_map_.find(device_location);
+
+ const AsyncDelegateKey key =
+ GetAsyncDelegateKey(device_location, read_only);
+ MTPDeviceUsageMap::iterator delegate_it = mtp_device_usage_map_.find(key);
DCHECK(delegate_it != mtp_device_usage_map_.end());
- mtp_device_usage_map_[device_location]--;
- if (mtp_device_usage_map_[device_location] == 0) {
+
+ mtp_device_usage_map_[key]--;
+ if (mtp_device_usage_map_[key] == 0) {
mtp_device_usage_map_.erase(delegate_it);
- RemoveAsyncDelegate(device_location);
+ RemoveAsyncDelegate(device_location, read_only);
}
}
}
void MTPDeviceMapService::AddAsyncDelegate(
const base::FilePath::StringType& device_location,
+ const bool read_only,
MTPDeviceAsyncDelegate* delegate) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(delegate);
DCHECK(!device_location.empty());
- if (ContainsKey(async_delegate_map_, device_location))
+
+ const AsyncDelegateKey key = GetAsyncDelegateKey(device_location, read_only);
+ if (ContainsKey(async_delegate_map_, key))
return;
- async_delegate_map_[device_location] = delegate;
+ async_delegate_map_[key] = delegate;
}
void MTPDeviceMapService::RemoveAsyncDelegate(
- const base::FilePath::StringType& device_location) {
+ const base::FilePath::StringType& device_location,
+ const bool read_only) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- AsyncDelegateMap::iterator it = async_delegate_map_.find(device_location);
+ DCHECK(!device_location.empty());
+
+ const AsyncDelegateKey key = GetAsyncDelegateKey(device_location, read_only);
+ AsyncDelegateMap::iterator it = async_delegate_map_.find(key);
DCHECK(it != async_delegate_map_.end());
it->second->CancelPendingTasksAndDeleteDelegate();
async_delegate_map_.erase(it);
}
+// static
+MTPDeviceMapService::AsyncDelegateKey MTPDeviceMapService::GetAsyncDelegateKey(
+ const base::FilePath::StringType& device_location,
+ const bool read_only) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ base::FilePath::StringType key;
+ key.append(read_only ? FILE_PATH_LITERAL("ReadOnly")
+ : FILE_PATH_LITERAL("ReadWrite"));
+ key.append(FILE_PATH_LITERAL("|"));
+ key.append(device_location);
+ return key;
+}
+
MTPDeviceAsyncDelegate* MTPDeviceMapService::GetMTPDeviceAsyncDelegate(
const std::string& filesystem_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ DCHECK(!filesystem_id.empty());
+
+ // File system may be already revoked on ExternalMountPoints side, we check
+ // here that the file system is still valid.
base::FilePath device_path;
if (!storage::ExternalMountPoints::GetSystemInstance()->GetRegisteredPath(
filesystem_id, &device_path)) {
@@ -91,10 +128,21 @@ MTPDeviceAsyncDelegate* MTPDeviceMapService::GetMTPDeviceAsyncDelegate(
}
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;
+
+ MTPDeviceFileSystemMap::const_iterator mtp_device_map_it =
+ mtp_device_map_.find(filesystem_id);
+ if (mtp_device_map_it == mtp_device_map_.end())
+ return NULL;
+
+ DCHECK_EQ(device_path.value(), mtp_device_map_it->second.first);
+ const bool read_only = mtp_device_map_it->second.second;
+ const AsyncDelegateKey key = GetAsyncDelegateKey(device_location, read_only);
+
+ AsyncDelegateMap::const_iterator async_delegate_map_it =
+ async_delegate_map_.find(key);
+ return (async_delegate_map_it != async_delegate_map_.end())
+ ? async_delegate_map_it->second
+ : NULL;
}
MTPDeviceMapService::MTPDeviceMapService() {
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h
index d64742e..0f24b14 100644
--- a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h
+++ b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h
@@ -29,14 +29,14 @@ class MTPDeviceMapService {
const std::string& filesystem_id);
// Register that an MTP filesystem is in use for the given |device_location|.
- void RegisterMTPFileSystem(
- const base::FilePath::StringType& device_location,
- const std::string& fsid);
+ void RegisterMTPFileSystem(const base::FilePath::StringType& device_location,
+ const std::string& filesystem_id,
+ const bool read_only);
// Removes the MTP entry associated with the given
// |device_location|. Signals the MTPDeviceMapService to destroy the
// delegate if there are no more uses of it.
- void RevokeMTPFileSystem(const std::string& fsid);
+ void RevokeMTPFileSystem(const std::string& filesystem_id);
private:
friend struct base::DefaultLazyInstanceTraits<MTPDeviceMapService>;
@@ -45,27 +45,34 @@ class MTPDeviceMapService {
// specifies the mount location of the MTP device.
// Called on the IO thread.
void AddAsyncDelegate(const base::FilePath::StringType& device_location,
+ const bool read_only,
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);
+ void RemoveAsyncDelegate(const base::FilePath::StringType& device_location,
+ const bool read_only);
+
+ // A key to be used in AsyncDelegateMap and MTPDeviceUsageMap.
+ typedef base::FilePath::StringType AsyncDelegateKey;
+
+ // Gets a key from |device_location| and |read_only|.
+ static AsyncDelegateKey GetAsyncDelegateKey(
+ const base::FilePath::StringType& device_location,
+ const bool read_only);
// 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;
+ typedef std::map<AsyncDelegateKey, MTPDeviceAsyncDelegate*> AsyncDelegateMap;
// Map a filesystem id (fsid) to an MTP device location.
- typedef std::map<std::string, base::FilePath::StringType>
- MTPDeviceFileSystemMap;
+ typedef std::pair<base::FilePath::StringType, bool> MTPDeviceInfo;
+ typedef std::map<std::string, MTPDeviceInfo> MTPDeviceFileSystemMap;
// Map a MTP or PTP device location to a count of current uses of that
// location.
- typedef std::map<const base::FilePath::StringType, int>
- MTPDeviceUsageMap;
-
+ typedef std::map<AsyncDelegateKey, int> MTPDeviceUsageMap;
// Get access to this class using GetInstance() method.
MTPDeviceMapService();
diff --git a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
index b1cd91c..b742eea8 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
+++ b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
@@ -4,11 +4,13 @@
#include "chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h"
+#include <fcntl.h>
#include <algorithm>
#include <vector>
#include "base/bind.h"
#include "base/numerics/safe_conversions.h"
+#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -51,13 +53,16 @@ std::string GetDeviceRelativePath(const base::FilePath& registered_dev_path,
// storage.
//
// |storage_name| specifies the name of the storage device.
+// |read_only| specifies the mode of the storage device.
// Returns NULL if the |storage_name| is no longer valid (e.g. because the
// corresponding storage device is detached, etc).
MTPDeviceTaskHelper* GetDeviceTaskHelperForStorage(
- const std::string& storage_name) {
+ const std::string& storage_name,
+ const bool read_only) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
return MTPDeviceTaskHelperMapService::GetInstance()->GetDeviceTaskHelper(
- storage_name);
+ storage_name,
+ read_only);
}
// Opens the storage device for communication.
@@ -66,20 +71,22 @@ MTPDeviceTaskHelper* GetDeviceTaskHelperForStorage(
// MediaTransferProtocolManager.
//
// |storage_name| specifies the name of the storage device.
+// |read_only| specifies the mode of the storage device.
// |reply_callback| is called when the OpenStorage request completes.
// |reply_callback| runs on the IO thread.
void OpenStorageOnUIThread(
const std::string& storage_name,
+ const bool read_only,
const MTPDeviceTaskHelper::OpenStorageCallback& reply_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
MTPDeviceTaskHelper* task_helper =
- GetDeviceTaskHelperForStorage(storage_name);
+ GetDeviceTaskHelperForStorage(storage_name, read_only);
if (!task_helper) {
task_helper =
MTPDeviceTaskHelperMapService::GetInstance()->CreateDeviceTaskHelper(
- storage_name);
+ storage_name, read_only);
}
- task_helper->OpenStorage(storage_name, reply_callback);
+ task_helper->OpenStorage(storage_name, read_only, reply_callback);
}
// Enumerates the |dir_id| directory file entries.
@@ -88,17 +95,19 @@ void OpenStorageOnUIThread(
// MediaTransferProtocolManager.
//
// |storage_name| specifies the name of the storage device.
+// |read_only| specifies the mode of the storage device.
// |success_callback| is called when the ReadDirectory request succeeds.
// |error_callback| is called when the ReadDirectory request fails.
// |success_callback| and |error_callback| runs on the IO thread.
void ReadDirectoryOnUIThread(
const std::string& storage_name,
+ const bool read_only,
uint32 dir_id,
const MTPDeviceTaskHelper::ReadDirectorySuccessCallback& success_callback,
const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
MTPDeviceTaskHelper* task_helper =
- GetDeviceTaskHelperForStorage(storage_name);
+ GetDeviceTaskHelperForStorage(storage_name, read_only);
if (!task_helper)
return;
task_helper->ReadDirectory(dir_id, success_callback, error_callback);
@@ -110,17 +119,19 @@ void ReadDirectoryOnUIThread(
// MediaTransferProtocolManager.
//
// |storage_name| specifies the name of the storage device.
+// |read_only| specifies the mode of the storage device.
// |success_callback| is called when the GetFileInfo request succeeds.
// |error_callback| is called when the GetFileInfo request fails.
// |success_callback| and |error_callback| runs on the IO thread.
void GetFileInfoOnUIThread(
const std::string& storage_name,
+ const bool read_only,
uint32 file_id,
const MTPDeviceTaskHelper::GetFileInfoSuccessCallback& success_callback,
const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
MTPDeviceTaskHelper* task_helper =
- GetDeviceTaskHelperForStorage(storage_name);
+ GetDeviceTaskHelperForStorage(storage_name, read_only);
if (!task_helper)
return;
task_helper->GetFileInfo(file_id, success_callback, error_callback);
@@ -132,6 +143,7 @@ void GetFileInfoOnUIThread(
// MediaTransferProtocolManager.
//
// |storage_name| specifies the name of the storage device.
+// |read_only| specifies the mode of the storage device.
// |device_file_path| specifies the media device file path.
// |snapshot_file_path| specifies the platform path of the snapshot file.
// |file_size| specifies the number of bytes that will be written to the
@@ -141,11 +153,12 @@ void GetFileInfoOnUIThread(
// |success_callback| and |error_callback| runs on the IO thread.
void WriteDataIntoSnapshotFileOnUIThread(
const std::string& storage_name,
+ const bool read_only,
const SnapshotRequestInfo& request_info,
const base::File::Info& snapshot_file_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
MTPDeviceTaskHelper* task_helper =
- GetDeviceTaskHelperForStorage(storage_name);
+ GetDeviceTaskHelperForStorage(storage_name, read_only);
if (!task_helper)
return;
task_helper->WriteDataIntoSnapshotFile(request_info, snapshot_file_info);
@@ -157,33 +170,80 @@ void WriteDataIntoSnapshotFileOnUIThread(
// MediaTransferProtocolManager.
//
// |storage_name| specifies the name of the storage device.
+// |read_only| specifies the mode of the storage device.
// |request| is a struct containing details about the byte read request.
void ReadBytesOnUIThread(
const std::string& storage_name,
+ const bool read_only,
const MTPDeviceAsyncDelegate::ReadBytesRequest& request) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
MTPDeviceTaskHelper* task_helper =
- GetDeviceTaskHelperForStorage(storage_name);
+ GetDeviceTaskHelperForStorage(storage_name, read_only);
if (!task_helper)
return;
task_helper->ReadBytes(request);
}
+// Copies the file |source_file_descriptor| to |file_name| in |parent_id|.
+//
+// |storage_name| specifies the name of the storage device.
+// |read_only| specifies the mode of the storage device.
+// |source_file_descriptor| file descriptor of source file.
+// |parent_id| object id of a target directory.
+// |file_name| file name of a target file.
+// |success_callback| is called when the file is copied successfully.
+// |error_callback| is called when it fails to copy file.
+// Since this method does not close the file descriptor, callbacks are
+// responsible for closing it.
+void CopyFileFromLocalOnUIThread(
+ const std::string& storage_name,
+ const bool read_only,
+ const int source_file_descriptor,
+ const uint32 parent_id,
+ const std::string& file_name,
+ const MTPDeviceTaskHelper::CopyFileFromLocalSuccessCallback&
+ success_callback,
+ const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ MTPDeviceTaskHelper* task_helper =
+ GetDeviceTaskHelperForStorage(storage_name, read_only);
+ if (!task_helper)
+ return;
+ task_helper->CopyFileFromLocal(storage_name, source_file_descriptor,
+ parent_id, file_name, success_callback,
+ error_callback);
+}
+
// Closes the device storage specified by the |storage_name| and destroys the
// MTPDeviceTaskHelper object associated with the device storage.
//
// Called on the UI thread to dispatch the request to the
// MediaTransferProtocolManager.
void CloseStorageAndDestroyTaskHelperOnUIThread(
- const std::string& storage_name) {
+ const std::string& storage_name,
+ const bool read_only) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
MTPDeviceTaskHelper* task_helper =
- GetDeviceTaskHelperForStorage(storage_name);
+ GetDeviceTaskHelperForStorage(storage_name, read_only);
if (!task_helper)
return;
task_helper->CloseStorage();
MTPDeviceTaskHelperMapService::GetInstance()->DestroyDeviceTaskHelper(
- storage_name);
+ storage_name, read_only);
+}
+
+// Opens |file_path| with |flags|.
+int OpenFileDescriptor(const char* file_path, const int flags) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+
+ return open(file_path, flags);
+}
+
+// Closes |file_descriptor| on file thread.
+void CloseFileDescriptor(const int file_descriptor) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+
+ IGNORE_EINTR(close(file_descriptor));
}
} // namespace
@@ -310,10 +370,12 @@ bool MTPDeviceDelegateImplLinux::MTPFileNode::DeleteChild(uint32 file_id) {
}
MTPDeviceDelegateImplLinux::MTPDeviceDelegateImplLinux(
- const std::string& device_location)
+ const std::string& device_location,
+ const bool read_only)
: init_state_(UNINITIALIZED),
task_in_progress_(false),
device_path_(device_location),
+ read_only_(read_only),
root_node_(new MTPFileNode(mtpd::kRootFileId,
"", // Root node has no name.
NULL, // And no parent node.
@@ -432,13 +494,41 @@ void MTPDeviceDelegateImplLinux::ReadBytes(
closure));
}
+bool MTPDeviceDelegateImplLinux::IsReadOnly() {
+ return read_only_;
+}
+
+void MTPDeviceDelegateImplLinux::CopyFileFromLocal(
+ const base::FilePath& source_file_path,
+ const base::FilePath& device_file_path,
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const ErrorCallback& error_callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ DCHECK(!source_file_path.empty());
+ DCHECK(!device_file_path.empty());
+
+ content::BrowserThread::PostTaskAndReplyWithResult(
+ content::BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&OpenFileDescriptor,
+ source_file_path.value().c_str(),
+ O_RDONLY),
+ base::Bind(&MTPDeviceDelegateImplLinux::CopyFileFromLocalInternal,
+ weak_ptr_factory_.GetWeakPtr(),
+ device_file_path,
+ success_callback,
+ error_callback));
+}
+
void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// To cancel all the pending tasks, destroy the MTPDeviceTaskHelper object.
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
- base::Bind(&CloseStorageAndDestroyTaskHelperOnUIThread, storage_name_));
+ base::Bind(&CloseStorageAndDestroyTaskHelperOnUIThread,
+ storage_name_,
+ read_only_));
delete this;
}
@@ -463,6 +553,7 @@ void MTPDeviceDelegateImplLinux::GetFileInfoInternal(
base::Closure closure = base::Bind(&GetFileInfoOnUIThread,
storage_name_,
+ read_only_,
file_id,
success_callback_wrapper,
error_callback_wrapper);
@@ -497,6 +588,7 @@ void MTPDeviceDelegateImplLinux::ReadDirectoryInternal(
dir_id);
base::Closure closure = base::Bind(&GetFileInfoOnUIThread,
storage_name_,
+ read_only_,
dir_id,
success_callback_wrapper,
error_callback_wrapper);
@@ -536,6 +628,7 @@ void MTPDeviceDelegateImplLinux::CreateSnapshotFileInternal(
file_id);
base::Closure closure = base::Bind(&GetFileInfoOnUIThread,
storage_name_,
+ read_only_,
file_id,
success_callback_wrapper,
error_callback_wrapper);
@@ -569,7 +662,7 @@ void MTPDeviceDelegateImplLinux::ReadBytesInternal(
file_id));
base::Closure closure =
- base::Bind(base::Bind(&ReadBytesOnUIThread, storage_name_, request));
+ base::Bind(&ReadBytesOnUIThread, storage_name_, read_only_, request);
EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
content::BrowserThread::UI,
FROM_HERE,
@@ -580,6 +673,49 @@ void MTPDeviceDelegateImplLinux::ReadBytesInternal(
PendingRequestDone();
}
+void MTPDeviceDelegateImplLinux::CopyFileFromLocalInternal(
+ const base::FilePath& device_file_path,
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const ErrorCallback& error_callback,
+ const int source_file_descriptor) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ if (source_file_descriptor < 0) {
+ error_callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
+ PendingRequestDone();
+ return;
+ }
+
+ uint32 parent_id;
+ if (CachedPathToId(device_file_path.DirName(), &parent_id)) {
+ CopyFileFromLocalSuccessCallback success_callback_wrapper =
+ base::Bind(&MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocal,
+ weak_ptr_factory_.GetWeakPtr(), success_callback,
+ source_file_descriptor);
+
+ ErrorCallback error_callback_wrapper = base::Bind(
+ &MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError,
+ weak_ptr_factory_.GetWeakPtr(), error_callback, source_file_descriptor);
+
+ base::Closure closure = base::Bind(&CopyFileFromLocalOnUIThread,
+ storage_name_,
+ read_only_,
+ source_file_descriptor,
+ parent_id,
+ device_file_path.BaseName().value(),
+ success_callback_wrapper,
+ error_callback_wrapper);
+
+ EnsureInitAndRunTask(PendingTaskInfo(
+ base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
+ } else {
+ HandleCopyFileFromLocalError(error_callback, source_file_descriptor,
+ base::File::FILE_ERROR_INVALID_OPERATION);
+ }
+
+ PendingRequestDone();
+}
+
void MTPDeviceDelegateImplLinux::EnsureInitAndRunTask(
const PendingTaskInfo& task_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
@@ -599,10 +735,8 @@ void MTPDeviceDelegateImplLinux::EnsureInitAndRunTask(
init_state_ = PENDING_INIT;
task_in_progress_ = true;
content::BrowserThread::PostTask(
- content::BrowserThread::UI,
- FROM_HERE,
- base::Bind(&OpenStorageOnUIThread,
- storage_name_,
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&OpenStorageOnUIThread, storage_name_, read_only_,
base::Bind(&MTPDeviceDelegateImplLinux::OnInitCompleted,
weak_ptr_factory_.GetWeakPtr())));
}
@@ -649,6 +783,7 @@ void MTPDeviceDelegateImplLinux::WriteDataIntoSnapshotFile(
base::Closure task_closure = base::Bind(&WriteDataIntoSnapshotFileOnUIThread,
storage_name_,
+ read_only_,
request_info,
file_info);
content::BrowserThread::PostTask(content::BrowserThread::UI,
@@ -657,6 +792,7 @@ void MTPDeviceDelegateImplLinux::WriteDataIntoSnapshotFile(
}
void MTPDeviceDelegateImplLinux::PendingRequestDone() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(task_in_progress_);
task_in_progress_ = false;
ProcessNextPendingRequest();
@@ -703,6 +839,7 @@ void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory(
base::Closure task_closure =
base::Bind(&ReadDirectoryOnUIThread,
storage_name_,
+ read_only_,
dir_id,
base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadDirectory,
weak_ptr_factory_.GetWeakPtr(),
@@ -854,6 +991,37 @@ void MTPDeviceDelegateImplLinux::OnFillFileCacheFailed(
pending_tasks_.front().path.clear();
}
+void MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocal(
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const int source_file_descriptor) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ const base::Closure closure = base::Bind(&CloseFileDescriptor,
+ source_file_descriptor);
+
+ content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
+ closure);
+
+ success_callback.Run();
+ PendingRequestDone();
+}
+
+void MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError(
+ const ErrorCallback& error_callback,
+ const int source_file_descriptor,
+ base::File::Error error) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ const base::Closure closure = base::Bind(&CloseFileDescriptor,
+ source_file_descriptor);
+
+ content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
+ closure);
+
+ error_callback.Run(error);
+ PendingRequestDone();
+}
+
void MTPDeviceDelegateImplLinux::HandleDeviceFileError(
const ErrorCallback& error_callback,
uint32 file_id,
@@ -943,7 +1111,8 @@ bool MTPDeviceDelegateImplLinux::CachedPathToId(const base::FilePath& path,
void CreateMTPDeviceAsyncDelegate(
const std::string& device_location,
+ const bool read_only,
const CreateMTPDeviceAsyncDelegateCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- callback.Run(new MTPDeviceDelegateImplLinux(device_location));
+ callback.Run(new MTPDeviceDelegateImplLinux(device_location, read_only));
}
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 0b9a7725..eba3703 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
@@ -32,6 +32,7 @@ class MTPDeviceDelegateImplLinux : public MTPDeviceAsyncDelegate {
private:
friend void CreateMTPDeviceAsyncDelegate(
const std::string&,
+ const bool read_only,
const CreateMTPDeviceAsyncDelegateCallback&);
enum InitializationState {
@@ -66,7 +67,8 @@ class MTPDeviceDelegateImplLinux : public MTPDeviceAsyncDelegate {
// Should only be called by CreateMTPDeviceAsyncDelegate() factory call.
// Defer the device initializations until the first file operation request.
// Do all the initializations in EnsureInitAndRunTask() function.
- explicit MTPDeviceDelegateImplLinux(const std::string& device_location);
+ MTPDeviceDelegateImplLinux(const std::string& device_location,
+ const bool read_only);
// Destructed via CancelPendingTasksAndDeleteDelegate().
~MTPDeviceDelegateImplLinux() override;
@@ -90,6 +92,12 @@ class MTPDeviceDelegateImplLinux : public MTPDeviceAsyncDelegate {
int buf_len,
const ReadBytesSuccessCallback& success_callback,
const ErrorCallback& error_callback) override;
+ bool IsReadOnly() override;
+ void CopyFileFromLocal(
+ const base::FilePath& source_file_path,
+ const base::FilePath& device_file_path,
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const ErrorCallback& error_callback) override;
void CancelPendingTasksAndDeleteDelegate() override;
// The internal methods correspond to the similarly named methods above.
@@ -112,6 +120,11 @@ class MTPDeviceDelegateImplLinux : public MTPDeviceAsyncDelegate {
net::IOBuffer* buf, int64 offset, int buf_len,
const ReadBytesSuccessCallback& success_callback,
const ErrorCallback& error_callback);
+ virtual void CopyFileFromLocalInternal(
+ const base::FilePath& device_file_path,
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const ErrorCallback& error_callback,
+ const int source_file_descriptor);
// Ensures the device is initialized for communication.
// If the device is already initialized, call RunTask().
@@ -222,6 +235,16 @@ class MTPDeviceDelegateImplLinux : public MTPDeviceAsyncDelegate {
// Called when FillFileCache() fails.
void OnFillFileCacheFailed(base::File::Error error);
+ // Called when CopyFileFromLocal() succeeds.
+ void OnDidCopyFileFromLocal(
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const int source_file_descriptor);
+
+ // Called when CopyFileFromLocal() fails.
+ void HandleCopyFileFromLocalError(const ErrorCallback& error_callback,
+ const int source_file_descriptor,
+ base::File::Error error);
+
// Handles the device file |error| while operating on |file_id|.
// |error_callback| is invoked to notify the caller about the file error.
void HandleDeviceFileError(const ErrorCallback& error_callback,
@@ -257,6 +280,9 @@ class MTPDeviceDelegateImplLinux : public MTPDeviceAsyncDelegate {
// MTP device storage name (e.g. "usb:2,2:81282").
std::string storage_name_;
+ // Mode for opening storage.
+ const bool read_only_;
+
// A list of pending tasks that needs to be run when the device is
// initialized or when the current task in progress is complete.
std::deque<PendingTaskInfo> pending_tasks_;
diff --git a/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc b/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc
index e19ce18..5fb766f 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc
+++ b/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc
@@ -59,6 +59,7 @@ MTPDeviceTaskHelper::~MTPDeviceTaskHelper() {
}
void MTPDeviceTaskHelper::OpenStorage(const std::string& storage_name,
+ const bool read_only,
const OpenStorageCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(!storage_name.empty());
@@ -68,11 +69,12 @@ void MTPDeviceTaskHelper::OpenStorage(const std::string& storage_name,
base::Bind(callback, true));
return;
}
+
+ const std::string mode =
+ read_only ? mtpd::kReadOnlyMode : mtpd::kReadWriteMode;
GetMediaTransferProtocolManager()->OpenStorage(
- storage_name, mtpd::kReadOnlyMode,
- base::Bind(&MTPDeviceTaskHelper::OnDidOpenStorage,
- weak_ptr_factory_.GetWeakPtr(),
- callback));
+ storage_name, mode, base::Bind(&MTPDeviceTaskHelper::OnDidOpenStorage,
+ weak_ptr_factory_.GetWeakPtr(), callback));
}
void MTPDeviceTaskHelper::GetFileInfo(
@@ -136,6 +138,22 @@ void MTPDeviceTaskHelper::ReadBytes(
weak_ptr_factory_.GetWeakPtr(), request));
}
+void MTPDeviceTaskHelper::CopyFileFromLocal(
+ const std::string& storage_name,
+ const int source_file_descriptor,
+ const uint32 parent_id,
+ const std::string& file_name,
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const ErrorCallback& error_callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ GetMediaTransferProtocolManager()->CopyFileFromLocal(
+ device_handle_, source_file_descriptor, parent_id, file_name,
+ base::Bind(&MTPDeviceTaskHelper::OnCopyFileFromLocal,
+ weak_ptr_factory_.GetWeakPtr(), success_callback,
+ error_callback));
+}
+
void MTPDeviceTaskHelper::CloseStorage() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (device_handle_.empty())
@@ -266,6 +284,22 @@ void MTPDeviceTaskHelper::OnDidReadBytes(
file_info, data.length()));
}
+void MTPDeviceTaskHelper::OnCopyFileFromLocal(
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const ErrorCallback& error_callback,
+ const bool error) const {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ if (error) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::Bind(error_callback, base::File::FILE_ERROR_FAILED));
+ return;
+ }
+
+ content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
+ base::Bind(success_callback));
+}
+
void MTPDeviceTaskHelper::HandleDeviceError(
const ErrorCallback& error_callback,
base::File::Error error) const {
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 31ac534..df284a1 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_task_helper.h
+++ b/chrome/browser/media_galleries/linux/mtp_device_task_helper.h
@@ -36,6 +36,8 @@ class MTPDeviceTaskHelper {
typedef base::Callback<void(const storage::AsyncFileUtil::EntryList& entries,
bool has_more)> ReadDirectorySuccessCallback;
+ typedef base::Closure CopyFileFromLocalSuccessCallback;
+
typedef MTPDeviceAsyncDelegate::ErrorCallback ErrorCallback;
MTPDeviceTaskHelper();
@@ -48,6 +50,7 @@ class MTPDeviceTaskHelper {
// |callback| is called when the OpenStorage request completes. |callback|
// runs on the IO thread.
void OpenStorage(const std::string& storage_name,
+ const bool read_only,
const OpenStorageCallback& callback);
// Dispatches the GetFileInfo request to the MediaTransferProtocolManager.
@@ -95,6 +98,15 @@ class MTPDeviceTaskHelper {
// called on the IO thread to notify the caller about success or failure.
void ReadBytes(const MTPDeviceAsyncDelegate::ReadBytesRequest& request);
+ // Forwards CopyFileFromLocal request to the MediaTransferProtocolManager.
+ void CopyFileFromLocal(
+ const std::string& storage_name,
+ const int source_file_descriptor,
+ const uint32 parent_id,
+ const std::string& file_name,
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const ErrorCallback& error_callback);
+
// Dispatches the CloseStorage request to the MediaTransferProtocolManager.
void CloseStorage() const;
@@ -159,6 +171,13 @@ class MTPDeviceTaskHelper {
const std::string& data,
bool error) const;
+ // Called when CopyFileFromLocal completed no matter if it succeeded or
+ // failed.
+ void OnCopyFileFromLocal(
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const ErrorCallback& error_callback,
+ const bool error) const;
+
// Called when the device is uninitialized.
//
// Runs |error_callback| on the IO thread to notify the caller about the
diff --git a/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.cc b/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.cc
index ce923aa..dfa85e3 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.cc
+++ b/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.cc
@@ -22,19 +22,25 @@ MTPDeviceTaskHelperMapService* MTPDeviceTaskHelperMapService::GetInstance() {
}
MTPDeviceTaskHelper* MTPDeviceTaskHelperMapService::CreateDeviceTaskHelper(
- const std::string& storage_name) {
+ const std::string& storage_name,
+ const bool read_only) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(!storage_name.empty());
- DCHECK(!ContainsKey(task_helper_map_, storage_name));
+ const MTPDeviceTaskHelperKey key =
+ GetMTPDeviceTaskHelperKey(storage_name, read_only);
+ DCHECK(!ContainsKey(task_helper_map_, key));
MTPDeviceTaskHelper* task_helper = new MTPDeviceTaskHelper();
- task_helper_map_[storage_name] = task_helper;
+ task_helper_map_[key] = task_helper;
return task_helper;
}
void MTPDeviceTaskHelperMapService::DestroyDeviceTaskHelper(
- const std::string& storage_name) {
+ const std::string& storage_name,
+ const bool read_only) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- TaskHelperMap::iterator it = task_helper_map_.find(storage_name);
+ const MTPDeviceTaskHelperKey key =
+ GetMTPDeviceTaskHelperKey(storage_name, read_only);
+ TaskHelperMap::iterator it = task_helper_map_.find(key);
if (it == task_helper_map_.end())
return;
delete it->second;
@@ -42,13 +48,25 @@ void MTPDeviceTaskHelperMapService::DestroyDeviceTaskHelper(
}
MTPDeviceTaskHelper* MTPDeviceTaskHelperMapService::GetDeviceTaskHelper(
- const std::string& storage_name) {
+ const std::string& storage_name,
+ const bool read_only) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(!storage_name.empty());
- TaskHelperMap::const_iterator it = task_helper_map_.find(storage_name);
+ const MTPDeviceTaskHelperKey key =
+ GetMTPDeviceTaskHelperKey(storage_name, read_only);
+ TaskHelperMap::const_iterator it = task_helper_map_.find(key);
return (it != task_helper_map_.end()) ? it->second : NULL;
}
+// static
+MTPDeviceTaskHelperMapService::MTPDeviceTaskHelperKey
+MTPDeviceTaskHelperMapService::GetMTPDeviceTaskHelperKey(
+ const std::string& storage_name,
+ const bool read_only) {
+ return (read_only ? "ReadOnly" : "ReadWrite") + std::string("|") +
+ storage_name;
+}
+
MTPDeviceTaskHelperMapService::MTPDeviceTaskHelperMapService() {
}
diff --git a/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.h b/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.h
index d13920c..6b02b09 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.h
+++ b/chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.h
@@ -20,25 +20,36 @@ class MTPDeviceTaskHelperMapService {
// Creates and returns the MTPDeviceTaskHelper object for the storage device
// specified by the |storage_name|.
- MTPDeviceTaskHelper* CreateDeviceTaskHelper(const std::string& storage_name);
+ MTPDeviceTaskHelper* CreateDeviceTaskHelper(const std::string& storage_name,
+ const bool read_only);
// Destroys the MTPDeviceTaskHelper object created by
// CreateDeviceTaskHelper().
// |storage_name| specifies the name of the storage device.
- void DestroyDeviceTaskHelper(const std::string& storage_name);
+ void DestroyDeviceTaskHelper(const std::string& storage_name,
+ const bool read_only);
// Gets the MTPDeviceTaskHelper object associated with the device storage.
// |storage_name| specifies the name of the storage device.
// Return NULL if the |storage_name| is no longer valid (e.g. because the
// corresponding storage device is detached, etc).
- MTPDeviceTaskHelper* GetDeviceTaskHelper(const std::string& storage_name);
+ MTPDeviceTaskHelper* GetDeviceTaskHelper(const std::string& storage_name,
+ const bool read_only);
private:
friend struct base::DefaultLazyInstanceTraits<MTPDeviceTaskHelperMapService>;
- // Key: Storage name.
+ // A key to be used in TaskHelperMap.
+ typedef std::string MTPDeviceTaskHelperKey;
+
+ // Gets a key from |storage_name| and |read_only|.
+ static MTPDeviceTaskHelperKey GetMTPDeviceTaskHelperKey(
+ const std::string& storage_name,
+ const bool read_only);
+
+ // Key: A combined value with storage_name and read_only.
// Value: MTPDeviceTaskHelper object.
- typedef std::map<std::string, MTPDeviceTaskHelper*> TaskHelperMap;
+ typedef std::map<MTPDeviceTaskHelperKey, MTPDeviceTaskHelper*> TaskHelperMap;
// Get access to this class using GetInstance() method.
MTPDeviceTaskHelperMapService();
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 0440fbd..f770834 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
@@ -54,6 +54,12 @@ class MTPDeviceDelegateImplMac : public MTPDeviceAsyncDelegate {
int buf_len,
const ReadBytesSuccessCallback& success_callback,
const ErrorCallback& error_callback) override;
+ bool IsReadOnly() override;
+ void CopyFileFromLocal(
+ const base::FilePath& source_file_path,
+ const base::FilePath& device_file_path,
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const ErrorCallback& error_callback) override;
void CancelPendingTasksAndDeleteDelegate() override;
// Forward delegates for ImageCaptureDeviceListener. These are
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 9c54cc7..a8781bc 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
@@ -209,6 +209,18 @@ void MTPDeviceDelegateImplMac::ReadBytes(
NOTREACHED();
}
+bool MTPDeviceDelegateImplMac::IsReadOnly() {
+ return true;
+}
+
+void MTPDeviceDelegateImplMac::CopyFileFromLocal(
+ const base::FilePath& source_file_path,
+ const base::FilePath& device_file_path,
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const ErrorCallback& error_callback) {
+ NOTREACHED();
+}
+
void MTPDeviceDelegateImplMac::CancelPendingTasksAndDeleteDelegate() {
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&MTPDeviceDelegateImplMac::CancelAndDelete,
@@ -480,7 +492,11 @@ MTPDeviceDelegateImplMac::ReadDirectoryRequest::~ReadDirectoryRequest() {}
void CreateMTPDeviceAsyncDelegate(
const base::FilePath::StringType& device_location,
+ const bool read_only,
const CreateMTPDeviceAsyncDelegateCallback& cb) {
+ // Write operation is not supported on Mac.
+ DCHECK(read_only);
+
std::string device_name = base::FilePath(device_location).BaseName().value();
std::string device_id;
storage_monitor::StorageInfo::Type type;
diff --git a/chrome/browser/media_galleries/media_file_system_registry.cc b/chrome/browser/media_galleries/media_file_system_registry.cc
index a01845e..85bd095 100644
--- a/chrome/browser/media_galleries/media_file_system_registry.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry.cc
@@ -722,10 +722,11 @@ class MediaFileSystemRegistry::MediaFileSystemContextImpl
storage::FileSystemMountOption(),
path);
CHECK(result);
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
- &MTPDeviceMapService::RegisterMTPFileSystem,
- base::Unretained(MTPDeviceMapService::GetInstance()),
- path.value(), fs_name));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&MTPDeviceMapService::RegisterMTPFileSystem,
+ base::Unretained(MTPDeviceMapService::GetInstance()),
+ path.value(), fs_name, true /* read only */));
return result;
}
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
index 21aa95e..5f1234c 100644
--- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
+++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
@@ -315,8 +315,13 @@ void OnGetStorageInfoCreateDelegate(
void CreateMTPDeviceAsyncDelegate(
const base::string16& device_location,
+ const bool read_only,
const CreateMTPDeviceAsyncDelegateCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ // Write operation is not supported on Windows.
+ DCHECK(read_only);
+
DCHECK(!device_location.empty());
base::string16* pnp_device_id = new base::string16;
base::string16* storage_object_id = new base::string16;
@@ -456,6 +461,18 @@ void MTPDeviceDelegateImplWin::ReadBytes(
NOTREACHED();
}
+bool MTPDeviceDelegateImplWin::IsReadOnly() {
+ return true;
+}
+
+void MTPDeviceDelegateImplWin::CopyFileFromLocal(
+ const base::FilePath& source_file_path,
+ const base::FilePath& device_file_path,
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const ErrorCallback& error_callback) {
+ NOTREACHED();
+}
+
void MTPDeviceDelegateImplWin::CancelPendingTasksAndDeleteDelegate() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
PortableDeviceMapService::GetInstance()->MarkPortableDeviceForDeletion(
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 f1ca860..f0da938 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
@@ -110,6 +110,12 @@ class MTPDeviceDelegateImplWin : public MTPDeviceAsyncDelegate {
int buf_len,
const ReadBytesSuccessCallback& success_callback,
const ErrorCallback& error_callback) override;
+ bool IsReadOnly() override;
+ void CopyFileFromLocal(
+ const base::FilePath& source_file_path,
+ const base::FilePath& device_file_path,
+ const CopyFileFromLocalSuccessCallback& success_callback,
+ const ErrorCallback& error_callback) override;
virtual void CancelPendingTasksAndDeleteDelegate() override;
// Ensures the device is initialized for communication by doing a
diff --git a/components/storage_monitor/test_media_transfer_protocol_manager_linux.cc b/components/storage_monitor/test_media_transfer_protocol_manager_linux.cc
index 42736db..572c626 100644
--- a/components/storage_monitor/test_media_transfer_protocol_manager_linux.cc
+++ b/components/storage_monitor/test_media_transfer_protocol_manager_linux.cc
@@ -66,4 +66,13 @@ void TestMediaTransferProtocolManagerLinux::GetFileInfo(
callback.Run(MtpFileEntry(), true);
}
+void TestMediaTransferProtocolManagerLinux::CopyFileFromLocal(
+ const std::string& storage_handle,
+ const int source_file_descriptor,
+ const uint32 parent_id,
+ const std::string& file_name,
+ const CopyFileFromLocalCallback& callback) {
+ callback.Run(true /* error */);
+}
+
} // namespace storage_monitor
diff --git a/components/storage_monitor/test_media_transfer_protocol_manager_linux.h b/components/storage_monitor/test_media_transfer_protocol_manager_linux.h
index 195c891..51d44c9 100644
--- a/components/storage_monitor/test_media_transfer_protocol_manager_linux.h
+++ b/components/storage_monitor/test_media_transfer_protocol_manager_linux.h
@@ -39,6 +39,11 @@ class TestMediaTransferProtocolManagerLinux
void GetFileInfo(const std::string& storage_handle,
uint32 file_id,
const GetFileInfoCallback& callback) override;
+ void CopyFileFromLocal(const std::string& storage_handle,
+ const int source_file_descriptor,
+ const uint32 parent_id,
+ const std::string& file_name,
+ const CopyFileFromLocalCallback& callback) override;
DISALLOW_COPY_AND_ASSIGN(TestMediaTransferProtocolManagerLinux);
};
diff --git a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc
index 0f72677..2dddbce 100644
--- a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc
+++ b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc
@@ -72,8 +72,8 @@ class MediaTransferProtocolDaemonClientImpl
dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kOpenStorage);
dbus::MessageWriter writer(&method_call);
writer.AppendString(storage_name);
- DCHECK_EQ(mtpd::kReadOnlyMode, mode);
- writer.AppendString(mtpd::kReadOnlyMode);
+ DCHECK(mode == mtpd::kReadOnlyMode || mode == mtpd::kReadWriteMode);
+ writer.AppendString(mode);
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&MediaTransferProtocolDaemonClientImpl::OnOpenStorage,
@@ -171,6 +171,28 @@ class MediaTransferProtocolDaemonClientImpl
error_callback));
}
+ void CopyFileFromLocal(const std::string& handle,
+ const int source_file_descriptor,
+ const uint32 parent_id,
+ const std::string& file_name,
+ const CopyFileFromLocalCallback& callback,
+ const ErrorCallback& error_callback) override {
+ dbus::FileDescriptor file_descriptor(source_file_descriptor);
+ file_descriptor.CheckValidity();
+
+ dbus::MethodCall method_call(mtpd::kMtpdInterface,
+ mtpd::kCopyFileFromLocal);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(handle);
+ writer.AppendFileDescriptor(file_descriptor);
+ writer.AppendUint32(parent_id);
+ writer.AppendString(file_name);
+ proxy_->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_INFINITE,
+ base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCopyFileFromLocal,
+ weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
+ }
+
// MediaTransferProtocolDaemonClient override.
void ListenForChanges(const MTPStorageEventHandler& handler) override {
DCHECK(!listen_for_changes_called_);
@@ -349,6 +371,17 @@ class MediaTransferProtocolDaemonClientImpl
callback.Run(data);
}
+ void OnCopyFileFromLocal(const CopyFileFromLocalCallback& callback,
+ const ErrorCallback& error_callback,
+ dbus::Response* response) {
+ if (!response) {
+ error_callback.Run();
+ return;
+ }
+
+ callback.Run();
+ }
+
// Handles MTPStorageAttached/Dettached signals and calls |handler|.
void OnMTPStorageSignal(MTPStorageEventHandler handler,
bool is_attach,
diff --git a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
index b051e6c..c44ba75 100644
--- a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
+++ b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
@@ -68,6 +68,9 @@ class MediaTransferProtocolDaemonClient {
// The argument is a string containing the file data.
typedef base::Callback<void(const std::string& data)> ReadFileCallback;
+ // A callback to handle the result of CopyFileFromLocal.
+ typedef base::Closure CopyFileFromLocalCallback;
+
// A callback to handle storage attach/detach events.
// The first argument is true for attach, false for detach.
// The second argument is the storage name.
@@ -137,6 +140,18 @@ class MediaTransferProtocolDaemonClient {
const ReadFileCallback& callback,
const ErrorCallback& error_callback) = 0;
+ // Calls CopyFileFromLocal method. |callback| is called after the method call
+ // succeeds, otherwise, |error_callback| is called.
+ // |source_file_descriptor| is a file descriptor of source file.
+ // |parent_id| is a object id of a target directory.
+ // |file_name| is a file name of a target file.
+ virtual void CopyFileFromLocal(const std::string& handle,
+ const int source_file_descriptor,
+ const uint32 parent_id,
+ const std::string& file_name,
+ const CopyFileFromLocalCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
// Registers given callback for events. Should only be called once.
// |storage_event_handler| is called when a mtp storage attach or detach
// signal is received.
diff --git a/device/media_transfer_protocol/media_transfer_protocol_manager.cc b/device/media_transfer_protocol/media_transfer_protocol_manager.cc
index cde9e53..fb59588 100644
--- a/device/media_transfer_protocol/media_transfer_protocol_manager.cc
+++ b/device/media_transfer_protocol/media_transfer_protocol_manager.cc
@@ -223,6 +223,25 @@ class MediaTransferProtocolManagerImpl : public MediaTransferProtocolManager {
weak_ptr_factory_.GetWeakPtr()));
}
+ void CopyFileFromLocal(const std::string& storage_handle,
+ const int source_file_descriptor,
+ const uint32 parent_id,
+ const std::string& file_name,
+ const CopyFileFromLocalCallback& callback) override {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
+ callback.Run(true /* error */);
+ return;
+ }
+ copy_file_from_local_callbacks_.push(callback);
+ mtp_client_->CopyFileFromLocal(
+ storage_handle, source_file_descriptor, parent_id, file_name,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnCopyFileFromLocal,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnCopyFileFromLocalError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
private:
// Map of storage names to storage info.
typedef std::map<std::string, MtpStorageInfo> StorageInfoMap;
@@ -235,6 +254,7 @@ class MediaTransferProtocolManagerImpl : public MediaTransferProtocolManager {
typedef std::queue<ReadDirectoryCallback> ReadDirectoryCallbackQueue;
typedef std::queue<ReadFileCallback> ReadFileCallbackQueue;
typedef std::queue<GetFileInfoCallback> GetFileInfoCallbackQueue;
+ typedef std::queue<CopyFileFromLocalCallback> CopyFileFromLocalCallbackQueue;
void OnStorageAttached(const std::string& storage_name) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -451,6 +471,18 @@ class MediaTransferProtocolManagerImpl : public MediaTransferProtocolManager {
get_file_info_callbacks_.pop();
}
+ void OnCopyFileFromLocal() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ copy_file_from_local_callbacks_.front().Run(false /* no error */);
+ copy_file_from_local_callbacks_.pop();
+ }
+
+ void OnCopyFileFromLocalError() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ copy_file_from_local_callbacks_.front().Run(true /* error */);
+ copy_file_from_local_callbacks_.pop();
+ }
+
// Get the Bus object used to communicate with mtpd.
dbus::Bus* GetBus() {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -532,6 +564,7 @@ class MediaTransferProtocolManagerImpl : public MediaTransferProtocolManager {
ReadDirectoryCallbackQueue read_directory_callbacks_;
ReadFileCallbackQueue read_file_callbacks_;
GetFileInfoCallbackQueue get_file_info_callbacks_;
+ CopyFileFromLocalCallbackQueue copy_file_from_local_callbacks_;
base::ThreadChecker thread_checker_;
diff --git a/device/media_transfer_protocol/media_transfer_protocol_manager.h b/device/media_transfer_protocol/media_transfer_protocol_manager.h
index 7ff89e9..39eea9b 100644
--- a/device/media_transfer_protocol/media_transfer_protocol_manager.h
+++ b/device/media_transfer_protocol/media_transfer_protocol_manager.h
@@ -59,6 +59,10 @@ class MediaTransferProtocolManager {
typedef base::Callback<void(const MtpFileEntry& file_entry,
bool error)> GetFileInfoCallback;
+ // A callback to handle the result of CopyFileFromLocal.
+ // The first argument is true if there was an error.
+ typedef base::Callback<void(bool error)> CopyFileFromLocalCallback;
+
// Implement this interface to be notified about MTP storage
// attachment / detachment events.
class Observer {
@@ -115,6 +119,14 @@ class MediaTransferProtocolManager {
uint32 file_id,
const GetFileInfoCallback& callback) = 0;
+ // Copies the file from |source_file_descriptor| to |file_name| on
+ // |parent_id|.
+ virtual void CopyFileFromLocal(const std::string& storage_handle,
+ const int source_file_descriptor,
+ const uint32 parent_id,
+ const std::string& file_name,
+ const CopyFileFromLocalCallback& callback) = 0;
+
// Creates and returns the global MediaTransferProtocolManager instance.
// On Linux, |task_runner| specifies the task runner to process asynchronous
// operations.