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