Home | History | Annotate | Download | only in linux
      1 // Copyright (c) 2012 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_read_file_worker.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/file_util.h"
      9 #include "base/files/file_path.h"
     10 #include "base/numerics/safe_conversions.h"
     11 #include "chrome/browser/media_galleries/linux/snapshot_file_details.h"
     12 #include "components/storage_monitor/storage_monitor.h"
     13 #include "content/public/browser/browser_thread.h"
     14 #include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
     15 #include "third_party/cros_system_api/dbus/service_constants.h"
     16 
     17 using content::BrowserThread;
     18 using storage_monitor::StorageMonitor;
     19 
     20 namespace {
     21 
     22 // Appends |data| to the snapshot file specified by the |snapshot_file_path| on
     23 // the file thread.
     24 // Returns the number of bytes written to the snapshot file. In case of failure,
     25 // returns zero.
     26 uint32 WriteDataChunkIntoSnapshotFileOnFileThread(
     27     const base::FilePath& snapshot_file_path,
     28     const std::string& data) {
     29   DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
     30   int bytes_written =
     31       base::AppendToFile(snapshot_file_path, data.data(),
     32                          base::checked_cast<int>(data.size()));
     33   return (static_cast<int>(data.size()) == bytes_written) ?
     34       base::checked_cast<uint32>(bytes_written) : 0;
     35 }
     36 
     37 }  // namespace
     38 
     39 MTPReadFileWorker::MTPReadFileWorker(const std::string& device_handle)
     40     : device_handle_(device_handle),
     41       weak_ptr_factory_(this) {
     42   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     43   DCHECK(!device_handle_.empty());
     44 }
     45 
     46 MTPReadFileWorker::~MTPReadFileWorker() {
     47 }
     48 
     49 void MTPReadFileWorker::WriteDataIntoSnapshotFile(
     50     const SnapshotRequestInfo& request_info,
     51     const base::File::Info& snapshot_file_info) {
     52   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     53   ReadDataChunkFromDeviceFile(
     54       make_scoped_ptr(new SnapshotFileDetails(request_info,
     55                                               snapshot_file_info)));
     56 }
     57 
     58 void MTPReadFileWorker::ReadDataChunkFromDeviceFile(
     59     scoped_ptr<SnapshotFileDetails> snapshot_file_details) {
     60   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     61   DCHECK(snapshot_file_details.get());
     62 
     63   // To avoid calling |snapshot_file_details| methods and passing ownership of
     64   // |snapshot_file_details| in the same_line.
     65   SnapshotFileDetails* snapshot_file_details_ptr = snapshot_file_details.get();
     66 
     67   device::MediaTransferProtocolManager* mtp_device_manager =
     68       StorageMonitor::GetInstance()->media_transfer_protocol_manager();
     69   mtp_device_manager->ReadFileChunkByPath(
     70       device_handle_,
     71       snapshot_file_details_ptr->device_file_path(),
     72       snapshot_file_details_ptr->bytes_written(),
     73       snapshot_file_details_ptr->BytesToRead(),
     74       base::Bind(&MTPReadFileWorker::OnDidReadDataChunkFromDeviceFile,
     75                  weak_ptr_factory_.GetWeakPtr(),
     76                  base::Passed(&snapshot_file_details)));
     77 }
     78 
     79 void MTPReadFileWorker::OnDidReadDataChunkFromDeviceFile(
     80     scoped_ptr<SnapshotFileDetails> snapshot_file_details,
     81     const std::string& data,
     82     bool error) {
     83   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     84   DCHECK(snapshot_file_details.get());
     85   snapshot_file_details->set_error_occurred(
     86       error || (data.size() != snapshot_file_details->BytesToRead()));
     87   if (snapshot_file_details->error_occurred()) {
     88     OnDidWriteIntoSnapshotFile(snapshot_file_details.Pass());
     89     return;
     90   }
     91 
     92   // To avoid calling |snapshot_file_details| methods and passing ownership of
     93   // |snapshot_file_details| in the same_line.
     94   SnapshotFileDetails* snapshot_file_details_ptr = snapshot_file_details.get();
     95   content::BrowserThread::PostTaskAndReplyWithResult(
     96       content::BrowserThread::FILE,
     97       FROM_HERE,
     98       base::Bind(&WriteDataChunkIntoSnapshotFileOnFileThread,
     99                  snapshot_file_details_ptr->snapshot_file_path(),
    100                  data),
    101       base::Bind(&MTPReadFileWorker::OnDidWriteDataChunkIntoSnapshotFile,
    102                  weak_ptr_factory_.GetWeakPtr(),
    103                  base::Passed(&snapshot_file_details)));
    104 }
    105 
    106 void MTPReadFileWorker::OnDidWriteDataChunkIntoSnapshotFile(
    107     scoped_ptr<SnapshotFileDetails> snapshot_file_details,
    108     uint32 bytes_written) {
    109   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    110   DCHECK(snapshot_file_details.get());
    111   if (snapshot_file_details->AddBytesWritten(bytes_written)) {
    112     if (!snapshot_file_details->IsSnapshotFileWriteComplete()) {
    113       ReadDataChunkFromDeviceFile(snapshot_file_details.Pass());
    114       return;
    115     }
    116   } else {
    117     snapshot_file_details->set_error_occurred(true);
    118   }
    119   OnDidWriteIntoSnapshotFile(snapshot_file_details.Pass());
    120 }
    121 
    122 void MTPReadFileWorker::OnDidWriteIntoSnapshotFile(
    123     scoped_ptr<SnapshotFileDetails> snapshot_file_details) {
    124   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
    125   DCHECK(snapshot_file_details.get());
    126 
    127   if (snapshot_file_details->error_occurred()) {
    128     content::BrowserThread::PostTask(
    129         content::BrowserThread::IO,
    130         FROM_HERE,
    131         base::Bind(snapshot_file_details->error_callback(),
    132                    base::File::FILE_ERROR_FAILED));
    133     return;
    134   }
    135   content::BrowserThread::PostTask(
    136       content::BrowserThread::IO,
    137       FROM_HERE,
    138       base::Bind(snapshot_file_details->success_callback(),
    139                  snapshot_file_details->file_info(),
    140                  snapshot_file_details->snapshot_file_path()));
    141 }
    142