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