Home | History | Annotate | Download | only in linux
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/media_galleries/linux/mtp_device_task_helper.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/logging.h"
     10 #include "base/numerics/safe_conversions.h"
     11 #include "chrome/browser/media_galleries/linux/mtp_device_object_enumerator.h"
     12 #include "chrome/browser/media_galleries/linux/mtp_read_file_worker.h"
     13 #include "chrome/browser/media_galleries/linux/snapshot_file_details.h"
     14 #include "components/storage_monitor/storage_monitor.h"
     15 #include "content/public/browser/browser_thread.h"
     16 #include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
     17 #include "net/base/io_buffer.h"
     18 #include "third_party/cros_system_api/dbus/service_constants.h"
     19 #include "webkit/browser/fileapi/async_file_util.h"
     20 #include "webkit/common/fileapi/file_system_util.h"
     21 
     22 using storage_monitor::StorageMonitor;
     23 
     24 namespace {
     25 
     26 // Does nothing.
     27 // This method is used to handle the results of
     28 // MediaTransferProtocolManager::CloseStorage method call.
     29 void DoNothing(bool error) {
     30 }
     31 
     32 device::MediaTransferProtocolManager* GetMediaTransferProtocolManager() {
     33   return StorageMonitor::GetInstance()->media_transfer_protocol_manager();
     34 }
     35 
     36 base::File::Info FileInfoFromMTPFileEntry(const MtpFileEntry& file_entry) {
     37   base::File::Info file_entry_info;
     38   file_entry_info.size = file_entry.file_size();
     39   file_entry_info.is_directory =
     40       file_entry.file_type() == MtpFileEntry::FILE_TYPE_FOLDER;
     41   file_entry_info.is_symbolic_link = false;
     42   file_entry_info.last_modified =
     43       base::Time::FromTimeT(file_entry.modification_time());
     44   file_entry_info.last_accessed = file_entry_info.last_modified;
     45   file_entry_info.creation_time = base::Time();
     46   return file_entry_info;
     47 }
     48 
     49 }  // namespace
     50 
     51 MTPDeviceTaskHelper::MTPDeviceTaskHelper()
     52     : weak_ptr_factory_(this) {
     53   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     54 }
     55 
     56 MTPDeviceTaskHelper::~MTPDeviceTaskHelper() {
     57   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     58 }
     59 
     60 void MTPDeviceTaskHelper::OpenStorage(const std::string& storage_name,
     61                                       const OpenStorageCallback& callback) {
     62   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     63   DCHECK(!storage_name.empty());
     64   if (!device_handle_.empty()) {
     65     content::BrowserThread::PostTask(content::BrowserThread::IO,
     66                                      FROM_HERE,
     67                                      base::Bind(callback, true));
     68     return;
     69   }
     70   GetMediaTransferProtocolManager()->OpenStorage(
     71       storage_name, mtpd::kReadOnlyMode,
     72       base::Bind(&MTPDeviceTaskHelper::OnDidOpenStorage,
     73                  weak_ptr_factory_.GetWeakPtr(),
     74                  callback));
     75 }
     76 
     77 void MTPDeviceTaskHelper::GetFileInfoByPath(
     78     const std::string& file_path,
     79     const GetFileInfoSuccessCallback& success_callback,
     80     const ErrorCallback& error_callback) {
     81   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     82   if (device_handle_.empty())
     83     return HandleDeviceError(error_callback, base::File::FILE_ERROR_FAILED);
     84 
     85   GetMediaTransferProtocolManager()->GetFileInfoByPath(
     86       device_handle_, file_path,
     87       base::Bind(&MTPDeviceTaskHelper::OnGetFileInfo,
     88                  weak_ptr_factory_.GetWeakPtr(),
     89                  success_callback,
     90                  error_callback));
     91 }
     92 
     93 void MTPDeviceTaskHelper::ReadDirectoryByPath(
     94     const std::string& dir_path,
     95     const ReadDirectorySuccessCallback& success_callback,
     96     const ErrorCallback& error_callback) {
     97   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     98   if (device_handle_.empty())
     99     return HandleDeviceError(error_callback, base::File::FILE_ERROR_FAILED);
    100 
    101   GetMediaTransferProtocolManager()->ReadDirectoryByPath(
    102       device_handle_, dir_path,
    103       base::Bind(&MTPDeviceTaskHelper::OnDidReadDirectoryByPath,
    104                  weak_ptr_factory_.GetWeakPtr(),
    105                  success_callback,
    106                  error_callback));
    107 }
    108 
    109 void MTPDeviceTaskHelper::WriteDataIntoSnapshotFile(
    110     const SnapshotRequestInfo& request_info,
    111     const base::File::Info& snapshot_file_info) {
    112   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    113   if (device_handle_.empty()) {
    114     return HandleDeviceError(request_info.error_callback,
    115                              base::File::FILE_ERROR_FAILED);
    116   }
    117 
    118   if (!read_file_worker_)
    119     read_file_worker_.reset(new MTPReadFileWorker(device_handle_));
    120   read_file_worker_->WriteDataIntoSnapshotFile(request_info,
    121                                                snapshot_file_info);
    122 }
    123 
    124 void MTPDeviceTaskHelper::ReadBytes(
    125     const MTPDeviceAsyncDelegate::ReadBytesRequest& request) {
    126   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    127   if (device_handle_.empty()) {
    128     return HandleDeviceError(request.error_callback,
    129                              base::File::FILE_ERROR_FAILED);
    130   }
    131 
    132   GetMediaTransferProtocolManager()->GetFileInfoByPath(
    133       device_handle_, request.device_file_relative_path,
    134       base::Bind(&MTPDeviceTaskHelper::OnGetFileInfoToReadBytes,
    135                  weak_ptr_factory_.GetWeakPtr(), request));
    136 }
    137 
    138 void MTPDeviceTaskHelper::CloseStorage() const {
    139   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    140   if (device_handle_.empty())
    141     return;
    142   GetMediaTransferProtocolManager()->CloseStorage(device_handle_,
    143                                                   base::Bind(&DoNothing));
    144 }
    145 
    146 void MTPDeviceTaskHelper::OnDidOpenStorage(
    147     const OpenStorageCallback& completion_callback,
    148     const std::string& device_handle,
    149     bool error) {
    150   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    151   device_handle_ = device_handle;
    152   content::BrowserThread::PostTask(content::BrowserThread::IO,
    153                                    FROM_HERE,
    154                                    base::Bind(completion_callback, !error));
    155 }
    156 
    157 void MTPDeviceTaskHelper::OnGetFileInfo(
    158     const GetFileInfoSuccessCallback& success_callback,
    159     const ErrorCallback& error_callback,
    160     const MtpFileEntry& file_entry,
    161     bool error) const {
    162   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    163   if (error) {
    164     return HandleDeviceError(error_callback,
    165                              base::File::FILE_ERROR_NOT_FOUND);
    166   }
    167 
    168   content::BrowserThread::PostTask(
    169       content::BrowserThread::IO,
    170       FROM_HERE,
    171       base::Bind(success_callback, FileInfoFromMTPFileEntry(file_entry)));
    172 }
    173 
    174 void MTPDeviceTaskHelper::OnDidReadDirectoryByPath(
    175     const ReadDirectorySuccessCallback& success_callback,
    176     const ErrorCallback& error_callback,
    177     const std::vector<MtpFileEntry>& file_entries,
    178     bool error) const {
    179   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    180   if (error)
    181     return HandleDeviceError(error_callback, base::File::FILE_ERROR_FAILED);
    182 
    183   fileapi::AsyncFileUtil::EntryList entries;
    184   base::FilePath current;
    185   MTPDeviceObjectEnumerator file_enum(file_entries);
    186   while (!(current = file_enum.Next()).empty()) {
    187     fileapi::DirectoryEntry entry;
    188     entry.name = fileapi::VirtualPath::BaseName(current).value();
    189     entry.is_directory = file_enum.IsDirectory();
    190     entry.size = file_enum.Size();
    191     entry.last_modified_time = file_enum.LastModifiedTime();
    192     entries.push_back(entry);
    193   }
    194   content::BrowserThread::PostTask(content::BrowserThread::IO,
    195                                    FROM_HERE,
    196                                    base::Bind(success_callback, entries));
    197 }
    198 
    199 void MTPDeviceTaskHelper::OnGetFileInfoToReadBytes(
    200     const MTPDeviceAsyncDelegate::ReadBytesRequest& request,
    201     const MtpFileEntry& file_entry,
    202     bool error) {
    203   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    204   DCHECK(request.buf);
    205   DCHECK(request.buf_len >= 0);
    206   DCHECK_GE(request.offset, 0);
    207   if (error) {
    208     return HandleDeviceError(request.error_callback,
    209                              base::File::FILE_ERROR_FAILED);
    210   }
    211 
    212   base::File::Info file_info = FileInfoFromMTPFileEntry(file_entry);
    213   if (file_info.is_directory) {
    214     return HandleDeviceError(request.error_callback,
    215                              base::File::FILE_ERROR_NOT_A_FILE);
    216   } else if (file_info.size < 0 || file_info.size > kuint32max ||
    217              request.offset > file_info.size) {
    218     return HandleDeviceError(request.error_callback,
    219                              base::File::FILE_ERROR_FAILED);
    220   } else if (request.offset == file_info.size) {
    221     content::BrowserThread::PostTask(content::BrowserThread::IO,
    222                                      FROM_HERE,
    223                                      base::Bind(request.success_callback,
    224                                                 file_info, 0u));
    225     return;
    226   }
    227 
    228   uint32 bytes_to_read = std::min(
    229       base::checked_cast<uint32>(request.buf_len),
    230       base::saturated_cast<uint32>(file_info.size - request.offset));
    231 
    232   GetMediaTransferProtocolManager()->ReadFileChunkByPath(
    233       device_handle_,
    234       request.device_file_relative_path,
    235       base::checked_cast<uint32>(request.offset),
    236       bytes_to_read,
    237       base::Bind(&MTPDeviceTaskHelper::OnDidReadBytes,
    238                  weak_ptr_factory_.GetWeakPtr(), request, file_info));
    239 }
    240 
    241 void MTPDeviceTaskHelper::OnDidReadBytes(
    242     const MTPDeviceAsyncDelegate::ReadBytesRequest& request,
    243     const base::File::Info& file_info,
    244     const std::string& data,
    245     bool error) const {
    246   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    247   if (error) {
    248     return HandleDeviceError(request.error_callback,
    249                              base::File::FILE_ERROR_FAILED);
    250   }
    251 
    252   CHECK_LE(base::checked_cast<int>(data.length()), request.buf_len);
    253   std::copy(data.begin(), data.end(), request.buf->data());
    254 
    255   content::BrowserThread::PostTask(content::BrowserThread::IO,
    256                                    FROM_HERE,
    257                                    base::Bind(request.success_callback,
    258                                               file_info, data.length()));
    259 }
    260 
    261 void MTPDeviceTaskHelper::HandleDeviceError(
    262     const ErrorCallback& error_callback,
    263     base::File::Error error) const {
    264   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    265   content::BrowserThread::PostTask(content::BrowserThread::IO,
    266                                    FROM_HERE,
    267                                    base::Bind(error_callback, error));
    268 }
    269