This source file includes following definitions.
- GetDeviceRelativePath
- GetDeviceTaskHelperForStorage
- OpenStorageOnUIThread
- ReadDirectoryOnUIThread
- GetFileInfoOnUIThread
- WriteDataIntoSnapshotFileOnUIThread
- ReadBytesOnUIThread
- CloseStorageAndDestroyTaskHelperOnUIThread
- task
- weak_ptr_factory_
- GetFileInfo
- ReadDirectory
- CreateSnapshotFile
- IsStreaming
- ReadBytes
- CancelPendingTasksAndDeleteDelegate
- EnsureInitAndRunTask
- WriteDataIntoSnapshotFile
- ProcessNextPendingRequest
- OnInitCompleted
- OnDidGetFileInfo
- OnDidGetFileInfoToReadDirectory
- OnDidGetFileInfoToCreateSnapshotFile
- OnDidReadDirectory
- OnDidWriteDataIntoSnapshotFile
- OnWriteDataIntoSnapshotFileError
- OnDidReadBytes
- HandleDeviceFileError
- CreateMTPDeviceAsyncDelegate
#include "chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h"
#include <algorithm>
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_util.h"
#include "chrome/browser/media_galleries/linux/mtp_device_task_helper.h"
#include "chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.h"
#include "chrome/browser/media_galleries/linux/snapshot_file_details.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/io_buffer.h"
namespace {
const char kRootPath[] = "/";
std::string GetDeviceRelativePath(const base::FilePath& registered_dev_path,
const base::FilePath& file_path) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(!registered_dev_path.empty());
DCHECK(!file_path.empty());
if (registered_dev_path == file_path)
return kRootPath;
base::FilePath relative_path;
if (!registered_dev_path.AppendRelativePath(file_path, &relative_path))
return std::string();
DCHECK(!relative_path.empty());
return relative_path.value();
}
MTPDeviceTaskHelper* GetDeviceTaskHelperForStorage(
const std::string& storage_name) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
return MTPDeviceTaskHelperMapService::GetInstance()->GetDeviceTaskHelper(
storage_name);
}
void OpenStorageOnUIThread(
const std::string& storage_name,
const base::Callback<void(bool)>& reply_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
MTPDeviceTaskHelper* task_helper =
GetDeviceTaskHelperForStorage(storage_name);
if (!task_helper) {
task_helper =
MTPDeviceTaskHelperMapService::GetInstance()->CreateDeviceTaskHelper(
storage_name);
}
task_helper->OpenStorage(storage_name, reply_callback);
}
void ReadDirectoryOnUIThread(
const std::string& storage_name,
const std::string& root,
const base::Callback<
void(const fileapi::AsyncFileUtil::EntryList&)>& success_callback,
const base::Callback<void(base::File::Error)>& error_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
MTPDeviceTaskHelper* task_helper =
GetDeviceTaskHelperForStorage(storage_name);
if (!task_helper)
return;
task_helper->ReadDirectoryByPath(root, success_callback, error_callback);
}
void GetFileInfoOnUIThread(
const std::string& storage_name,
const std::string& file_path,
const base::Callback<void(const base::File::Info&)>& success_callback,
const base::Callback<void(base::File::Error)>& error_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
MTPDeviceTaskHelper* task_helper =
GetDeviceTaskHelperForStorage(storage_name);
if (!task_helper)
return;
task_helper->GetFileInfoByPath(file_path, success_callback, error_callback);
}
void WriteDataIntoSnapshotFileOnUIThread(
const std::string& storage_name,
const SnapshotRequestInfo& request_info,
const base::File::Info& snapshot_file_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
MTPDeviceTaskHelper* task_helper =
GetDeviceTaskHelperForStorage(storage_name);
if (!task_helper)
return;
task_helper->WriteDataIntoSnapshotFile(request_info, snapshot_file_info);
}
void ReadBytesOnUIThread(
const std::string& storage_name,
const MTPDeviceAsyncDelegate::ReadBytesRequest& request) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
MTPDeviceTaskHelper* task_helper =
GetDeviceTaskHelperForStorage(storage_name);
if (!task_helper)
return;
task_helper->ReadBytes(request);
}
void CloseStorageAndDestroyTaskHelperOnUIThread(
const std::string& storage_name) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
MTPDeviceTaskHelper* task_helper =
GetDeviceTaskHelperForStorage(storage_name);
if (!task_helper)
return;
task_helper->CloseStorage();
MTPDeviceTaskHelperMapService::GetInstance()->DestroyDeviceTaskHelper(
storage_name);
}
}
MTPDeviceDelegateImplLinux::PendingTaskInfo::PendingTaskInfo(
const tracked_objects::Location& location,
const base::Closure& task)
: location(location),
task(task) {
}
MTPDeviceDelegateImplLinux::PendingTaskInfo::~PendingTaskInfo() {
}
MTPDeviceDelegateImplLinux::MTPDeviceDelegateImplLinux(
const std::string& device_location)
: init_state_(UNINITIALIZED),
task_in_progress_(false),
device_path_(device_location),
weak_ptr_factory_(this) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(!device_path_.empty());
base::RemoveChars(device_location, kRootPath, &storage_name_);
DCHECK(!storage_name_.empty());
}
MTPDeviceDelegateImplLinux::~MTPDeviceDelegateImplLinux() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
}
void MTPDeviceDelegateImplLinux::GetFileInfo(
const base::FilePath& file_path,
const GetFileInfoSuccessCallback& success_callback,
const ErrorCallback& error_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(!file_path.empty());
base::Closure call_closure =
base::Bind(&GetFileInfoOnUIThread,
storage_name_,
GetDeviceRelativePath(device_path_, file_path),
base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfo,
weak_ptr_factory_.GetWeakPtr(),
success_callback),
base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
weak_ptr_factory_.GetWeakPtr(),
error_callback));
EnsureInitAndRunTask(PendingTaskInfo(FROM_HERE, call_closure));
}
void MTPDeviceDelegateImplLinux::ReadDirectory(
const base::FilePath& root,
const ReadDirectorySuccessCallback& success_callback,
const ErrorCallback& error_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(!root.empty());
std::string device_file_relative_path = GetDeviceRelativePath(device_path_,
root);
base::Closure call_closure =
base::Bind(
&GetFileInfoOnUIThread,
storage_name_,
device_file_relative_path,
base::Bind(
&MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory,
weak_ptr_factory_.GetWeakPtr(),
device_file_relative_path,
success_callback,
error_callback),
base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
weak_ptr_factory_.GetWeakPtr(),
error_callback));
EnsureInitAndRunTask(PendingTaskInfo(FROM_HERE, call_closure));
}
void MTPDeviceDelegateImplLinux::CreateSnapshotFile(
const base::FilePath& device_file_path,
const base::FilePath& snapshot_file_path,
const CreateSnapshotFileSuccessCallback& success_callback,
const ErrorCallback& error_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(!device_file_path.empty());
DCHECK(!snapshot_file_path.empty());
std::string device_file_relative_path =
GetDeviceRelativePath(device_path_, device_file_path);
scoped_ptr<SnapshotRequestInfo> request_info(
new SnapshotRequestInfo(device_file_relative_path,
snapshot_file_path,
success_callback,
error_callback));
base::Closure call_closure =
base::Bind(
&GetFileInfoOnUIThread,
storage_name_,
device_file_relative_path,
base::Bind(
&MTPDeviceDelegateImplLinux::OnDidGetFileInfoToCreateSnapshotFile,
weak_ptr_factory_.GetWeakPtr(),
base::Passed(&request_info)),
base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
weak_ptr_factory_.GetWeakPtr(),
error_callback));
EnsureInitAndRunTask(PendingTaskInfo(FROM_HERE, call_closure));
}
bool MTPDeviceDelegateImplLinux::IsStreaming() {
return true;
}
void MTPDeviceDelegateImplLinux::ReadBytes(
const base::FilePath& device_file_path,
net::IOBuffer* buf, int64 offset, int buf_len,
const ReadBytesSuccessCallback& success_callback,
const ErrorCallback& error_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(!device_file_path.empty());
std::string device_file_relative_path =
GetDeviceRelativePath(device_path_, device_file_path);
ReadBytesRequest request(
device_file_relative_path, buf, offset, buf_len,
base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadBytes,
weak_ptr_factory_.GetWeakPtr(), success_callback),
base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
weak_ptr_factory_.GetWeakPtr(), error_callback));
base::Closure call_closure =
base::Bind(base::Bind(&ReadBytesOnUIThread, storage_name_, request));
EnsureInitAndRunTask(PendingTaskInfo(FROM_HERE, call_closure));
}
void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&CloseStorageAndDestroyTaskHelperOnUIThread, storage_name_));
delete this;
}
void MTPDeviceDelegateImplLinux::EnsureInitAndRunTask(
const PendingTaskInfo& task_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if ((init_state_ == INITIALIZED) && !task_in_progress_) {
task_in_progress_ = true;
content::BrowserThread::PostTask(content::BrowserThread::UI,
task_info.location,
task_info.task);
return;
}
pending_tasks_.push(task_info);
if (init_state_ == UNINITIALIZED) {
init_state_ = PENDING_INIT;
task_in_progress_ = true;
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&OpenStorageOnUIThread,
storage_name_,
base::Bind(&MTPDeviceDelegateImplLinux::OnInitCompleted,
weak_ptr_factory_.GetWeakPtr())));
}
}
void MTPDeviceDelegateImplLinux::WriteDataIntoSnapshotFile(
const base::File::Info& file_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(current_snapshot_request_info_.get());
DCHECK_GT(file_info.size, 0);
task_in_progress_ = true;
SnapshotRequestInfo request_info(
current_snapshot_request_info_->device_file_path,
current_snapshot_request_info_->snapshot_file_path,
base::Bind(
&MTPDeviceDelegateImplLinux::OnDidWriteDataIntoSnapshotFile,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(
&MTPDeviceDelegateImplLinux::OnWriteDataIntoSnapshotFileError,
weak_ptr_factory_.GetWeakPtr()));
base::Closure task_closure = base::Bind(&WriteDataIntoSnapshotFileOnUIThread,
storage_name_,
request_info,
file_info);
content::BrowserThread::PostTask(content::BrowserThread::UI,
FROM_HERE,
task_closure);
}
void MTPDeviceDelegateImplLinux::ProcessNextPendingRequest() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(!task_in_progress_);
if (pending_tasks_.empty())
return;
task_in_progress_ = true;
const PendingTaskInfo& task_info = pending_tasks_.front();
content::BrowserThread::PostTask(content::BrowserThread::UI,
task_info.location,
task_info.task);
pending_tasks_.pop();
}
void MTPDeviceDelegateImplLinux::OnInitCompleted(bool succeeded) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
init_state_ = succeeded ? INITIALIZED : UNINITIALIZED;
task_in_progress_ = false;
ProcessNextPendingRequest();
}
void MTPDeviceDelegateImplLinux::OnDidGetFileInfo(
const GetFileInfoSuccessCallback& success_callback,
const base::File::Info& file_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
success_callback.Run(file_info);
task_in_progress_ = false;
ProcessNextPendingRequest();
}
void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory(
const std::string& root,
const ReadDirectorySuccessCallback& success_callback,
const ErrorCallback& error_callback,
const base::File::Info& file_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(task_in_progress_);
if (!file_info.is_directory) {
return HandleDeviceFileError(error_callback,
base::File::FILE_ERROR_NOT_A_DIRECTORY);
}
base::Closure task_closure =
base::Bind(&ReadDirectoryOnUIThread,
storage_name_,
root,
base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadDirectory,
weak_ptr_factory_.GetWeakPtr(),
success_callback),
base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
weak_ptr_factory_.GetWeakPtr(),
error_callback));
content::BrowserThread::PostTask(content::BrowserThread::UI,
FROM_HERE,
task_closure);
}
void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToCreateSnapshotFile(
scoped_ptr<SnapshotRequestInfo> snapshot_request_info,
const base::File::Info& file_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(!current_snapshot_request_info_.get());
DCHECK(snapshot_request_info.get());
DCHECK(task_in_progress_);
base::File::Error error = base::File::FILE_OK;
if (file_info.is_directory)
error = base::File::FILE_ERROR_NOT_A_FILE;
else if (file_info.size < 0 || file_info.size > kuint32max)
error = base::File::FILE_ERROR_FAILED;
if (error != base::File::FILE_OK)
return HandleDeviceFileError(snapshot_request_info->error_callback, error);
base::File::Info snapshot_file_info(file_info);
snapshot_file_info.last_modified = base::Time();
current_snapshot_request_info_.reset(snapshot_request_info.release());
if (file_info.size == 0) {
return OnDidWriteDataIntoSnapshotFile(
snapshot_file_info, current_snapshot_request_info_->snapshot_file_path);
}
WriteDataIntoSnapshotFile(snapshot_file_info);
}
void MTPDeviceDelegateImplLinux::OnDidReadDirectory(
const ReadDirectorySuccessCallback& success_callback,
const fileapi::AsyncFileUtil::EntryList& file_list) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
success_callback.Run(file_list, false );
task_in_progress_ = false;
ProcessNextPendingRequest();
}
void MTPDeviceDelegateImplLinux::OnDidWriteDataIntoSnapshotFile(
const base::File::Info& file_info,
const base::FilePath& snapshot_file_path) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(current_snapshot_request_info_.get());
DCHECK(task_in_progress_);
current_snapshot_request_info_->success_callback.Run(
file_info, snapshot_file_path);
task_in_progress_ = false;
current_snapshot_request_info_.reset();
ProcessNextPendingRequest();
}
void MTPDeviceDelegateImplLinux::OnWriteDataIntoSnapshotFileError(
base::File::Error error) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(current_snapshot_request_info_.get());
DCHECK(task_in_progress_);
current_snapshot_request_info_->error_callback.Run(error);
task_in_progress_ = false;
current_snapshot_request_info_.reset();
ProcessNextPendingRequest();
}
void MTPDeviceDelegateImplLinux::OnDidReadBytes(
const ReadBytesSuccessCallback& success_callback,
const base::File::Info& file_info, int bytes_read) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(task_in_progress_);
success_callback.Run(file_info, bytes_read);
task_in_progress_ = false;
ProcessNextPendingRequest();
}
void MTPDeviceDelegateImplLinux::HandleDeviceFileError(
const ErrorCallback& error_callback,
base::File::Error error) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(task_in_progress_);
error_callback.Run(error);
task_in_progress_ = false;
ProcessNextPendingRequest();
}
void CreateMTPDeviceAsyncDelegate(
const std::string& device_location,
const CreateMTPDeviceAsyncDelegateCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
callback.Run(new MTPDeviceDelegateImplLinux(device_location));
}