[Cronet] Delay StartNetLog and StopNetLog until native request context is initialized
[chromium-blink-merge.git] / chrome / browser / media_galleries / linux / mtp_device_delegate_impl_linux.cc
blobd0b1fd966f4790ff979e1b69b2e25950bd633f4f
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.
5 #include "chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h"
7 #include <fcntl.h>
8 #include <algorithm>
9 #include <vector>
11 #include "base/bind.h"
12 #include "base/files/file_util.h"
13 #include "base/numerics/safe_conversions.h"
14 #include "base/posix/eintr_wrapper.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_split.h"
17 #include "base/strings/string_util.h"
18 #include "chrome/browser/media_galleries/linux/mtp_device_task_helper.h"
19 #include "chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.h"
20 #include "chrome/browser/media_galleries/linux/snapshot_file_details.h"
21 #include "net/base/io_buffer.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
24 namespace {
26 // File path separator constant.
27 const char kRootPath[] = "/";
29 // Returns the device relative file path given |file_path|.
30 // E.g.: If the |file_path| is "/usb:2,2:12345/DCIM" and |registered_dev_path|
31 // is "/usb:2,2:12345", this function returns the device relative path which is
32 // "DCIM".
33 // In the special case when |registered_dev_path| and |file_path| are the same,
34 // return |kRootPath|.
35 std::string GetDeviceRelativePath(const base::FilePath& registered_dev_path,
36 const base::FilePath& file_path) {
37 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
38 DCHECK(!registered_dev_path.empty());
39 DCHECK(!file_path.empty());
40 std::string result;
41 if (registered_dev_path == file_path) {
42 result = kRootPath;
43 } else {
44 base::FilePath relative_path;
45 if (registered_dev_path.AppendRelativePath(file_path, &relative_path)) {
46 DCHECK(!relative_path.empty());
47 result = relative_path.value();
50 return result;
53 // Returns the MTPDeviceTaskHelper object associated with the MTP device
54 // storage.
56 // |storage_name| specifies the name of the storage device.
57 // |read_only| specifies the mode of the storage device.
58 // Returns NULL if the |storage_name| is no longer valid (e.g. because the
59 // corresponding storage device is detached, etc).
60 MTPDeviceTaskHelper* GetDeviceTaskHelperForStorage(
61 const std::string& storage_name,
62 const bool read_only) {
63 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
64 return MTPDeviceTaskHelperMapService::GetInstance()->GetDeviceTaskHelper(
65 storage_name,
66 read_only);
69 // Opens the storage device for communication.
71 // Called on the UI thread to dispatch the request to the
72 // MediaTransferProtocolManager.
74 // |storage_name| specifies the name of the storage device.
75 // |read_only| specifies the mode of the storage device.
76 // |reply_callback| is called when the OpenStorage request completes.
77 // |reply_callback| runs on the IO thread.
78 void OpenStorageOnUIThread(
79 const std::string& storage_name,
80 const bool read_only,
81 const MTPDeviceTaskHelper::OpenStorageCallback& reply_callback) {
82 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
83 MTPDeviceTaskHelper* task_helper =
84 GetDeviceTaskHelperForStorage(storage_name, read_only);
85 if (!task_helper) {
86 task_helper =
87 MTPDeviceTaskHelperMapService::GetInstance()->CreateDeviceTaskHelper(
88 storage_name, read_only);
90 task_helper->OpenStorage(storage_name, read_only, reply_callback);
93 // Enumerates the |dir_id| directory file entries.
95 // Called on the UI thread to dispatch the request to the
96 // MediaTransferProtocolManager.
98 // |storage_name| specifies the name of the storage device.
99 // |read_only| specifies the mode of the storage device.
100 // |directory_id| is an id of a directory to read.
101 // |max_size| is a maximum size to read. Set 0 not to specify the maximum size.
102 // |success_callback| is called when the ReadDirectory request succeeds.
103 // |error_callback| is called when the ReadDirectory request fails.
104 // |success_callback| and |error_callback| runs on the IO thread.
105 void ReadDirectoryOnUIThread(
106 const std::string& storage_name,
107 const bool read_only,
108 const uint32 directory_id,
109 const size_t max_size,
110 const MTPDeviceTaskHelper::ReadDirectorySuccessCallback& success_callback,
111 const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
112 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
113 MTPDeviceTaskHelper* task_helper =
114 GetDeviceTaskHelperForStorage(storage_name, read_only);
115 if (!task_helper)
116 return;
117 task_helper->ReadDirectory(directory_id, max_size, success_callback,
118 error_callback);
121 // Gets the |file_path| details.
123 // Called on the UI thread to dispatch the request to the
124 // MediaTransferProtocolManager.
126 // |storage_name| specifies the name of the storage device.
127 // |read_only| specifies the mode of the storage device.
128 // |success_callback| is called when the GetFileInfo request succeeds.
129 // |error_callback| is called when the GetFileInfo request fails.
130 // |success_callback| and |error_callback| runs on the IO thread.
131 void GetFileInfoOnUIThread(
132 const std::string& storage_name,
133 const bool read_only,
134 uint32 file_id,
135 const MTPDeviceTaskHelper::GetFileInfoSuccessCallback& success_callback,
136 const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
137 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
138 MTPDeviceTaskHelper* task_helper =
139 GetDeviceTaskHelperForStorage(storage_name, read_only);
140 if (!task_helper)
141 return;
142 task_helper->GetFileInfo(file_id, success_callback, error_callback);
145 // Copies the contents of |device_file_path| to |snapshot_file_path|.
147 // Called on the UI thread to dispatch the request to the
148 // MediaTransferProtocolManager.
150 // |storage_name| specifies the name of the storage device.
151 // |read_only| specifies the mode of the storage device.
152 // |device_file_path| specifies the media device file path.
153 // |snapshot_file_path| specifies the platform path of the snapshot file.
154 // |file_size| specifies the number of bytes that will be written to the
155 // snapshot file.
156 // |success_callback| is called when the copy operation succeeds.
157 // |error_callback| is called when the copy operation fails.
158 // |success_callback| and |error_callback| runs on the IO thread.
159 void WriteDataIntoSnapshotFileOnUIThread(
160 const std::string& storage_name,
161 const bool read_only,
162 const SnapshotRequestInfo& request_info,
163 const base::File::Info& snapshot_file_info) {
164 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
165 MTPDeviceTaskHelper* task_helper =
166 GetDeviceTaskHelperForStorage(storage_name, read_only);
167 if (!task_helper)
168 return;
169 task_helper->WriteDataIntoSnapshotFile(request_info, snapshot_file_info);
172 // Copies the contents of |device_file_path| to |snapshot_file_path|.
174 // Called on the UI thread to dispatch the request to the
175 // MediaTransferProtocolManager.
177 // |storage_name| specifies the name of the storage device.
178 // |read_only| specifies the mode of the storage device.
179 // |request| is a struct containing details about the byte read request.
180 void ReadBytesOnUIThread(
181 const std::string& storage_name,
182 const bool read_only,
183 const MTPDeviceAsyncDelegate::ReadBytesRequest& request) {
184 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
185 MTPDeviceTaskHelper* task_helper =
186 GetDeviceTaskHelperForStorage(storage_name, read_only);
187 if (!task_helper)
188 return;
189 task_helper->ReadBytes(request);
192 // Renames |object_id| to |new_name|.
194 // |storage_name| specifies the name of the storage device.
195 // |read_only| specifies the mode of the storage device.
196 // |object_id| is an id of object to be renamed.
197 // |new_name| is new name of the object.
198 // |success_callback| is called when the object is renamed successfully.
199 // |error_callback| is called when it fails to rename the object.
200 // |success_callback| and |error_callback| runs on the IO thread.
201 void RenameObjectOnUIThread(
202 const std::string& storage_name,
203 const bool read_only,
204 const uint32 object_id,
205 const std::string& new_name,
206 const MTPDeviceTaskHelper::RenameObjectSuccessCallback& success_callback,
207 const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
208 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
209 MTPDeviceTaskHelper* task_helper =
210 GetDeviceTaskHelperForStorage(storage_name, read_only);
211 if (!task_helper)
212 return;
213 task_helper->RenameObject(object_id, new_name, success_callback,
214 error_callback);
217 // Copies the file |source_file_descriptor| to |file_name| in |parent_id|.
219 // |storage_name| specifies the name of the storage device.
220 // |read_only| specifies the mode of the storage device.
221 // |source_file_descriptor| file descriptor of source file.
222 // |parent_id| object id of a target directory.
223 // |file_name| file name of a target file.
224 // |success_callback| is called when the file is copied successfully.
225 // |error_callback| is called when it fails to copy file.
226 // Since this method does not close the file descriptor, callbacks are
227 // responsible for closing it.
228 void CopyFileFromLocalOnUIThread(
229 const std::string& storage_name,
230 const bool read_only,
231 const int source_file_descriptor,
232 const uint32 parent_id,
233 const std::string& file_name,
234 const MTPDeviceTaskHelper::CopyFileFromLocalSuccessCallback&
235 success_callback,
236 const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
237 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
238 MTPDeviceTaskHelper* task_helper =
239 GetDeviceTaskHelperForStorage(storage_name, read_only);
240 if (!task_helper)
241 return;
242 task_helper->CopyFileFromLocal(storage_name, source_file_descriptor,
243 parent_id, file_name, success_callback,
244 error_callback);
247 // Deletes |object_id|.
249 // Called on the UI thread to dispatch the request to the
250 // MediaTransferProtocolManager.
252 // |storage_name| specifies the name of the storage device.
253 // |read_only| specifies the mode of the storage device.
254 // |object_id| is the object to be deleted.
255 // |success_callback| is called when the object is deleted successfully.
256 // |error_callback| is called when it fails to delete the object.
257 // |success_callback| and |error_callback| runs on the IO thread.
258 void DeleteObjectOnUIThread(
259 const std::string storage_name,
260 const bool read_only,
261 const uint32 object_id,
262 const MTPDeviceTaskHelper::DeleteObjectSuccessCallback success_callback,
263 const MTPDeviceTaskHelper::ErrorCallback error_callback) {
264 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
265 MTPDeviceTaskHelper* task_helper =
266 GetDeviceTaskHelperForStorage(storage_name, read_only);
267 if (!task_helper)
268 return;
269 task_helper->DeleteObject(object_id, success_callback, error_callback);
272 // Closes the device storage specified by the |storage_name| and destroys the
273 // MTPDeviceTaskHelper object associated with the device storage.
275 // Called on the UI thread to dispatch the request to the
276 // MediaTransferProtocolManager.
277 void CloseStorageAndDestroyTaskHelperOnUIThread(
278 const std::string& storage_name,
279 const bool read_only) {
280 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
281 MTPDeviceTaskHelper* task_helper =
282 GetDeviceTaskHelperForStorage(storage_name, read_only);
283 if (!task_helper)
284 return;
285 task_helper->CloseStorage();
286 MTPDeviceTaskHelperMapService::GetInstance()->DestroyDeviceTaskHelper(
287 storage_name, read_only);
290 // Opens |file_path| with |flags|. Returns the result as a pair.
291 // first is file descriptor.
292 // second is base::File::Error. This value is set as following.
293 // - When it succeeds to open a file descriptor, base::File::FILE_OK is set.
294 // - When |file_path| is a directory, base::File::FILE_ERROR_NOT_A_FILE is set.
295 // - When |file_path| does not exist, base::File::FILE_ERROR_NOT_FOUND is set.
296 // - For other error cases, base::File::FILE_ERROR_FAILED is set.
297 std::pair<int, base::File::Error> OpenFileDescriptor(const char* file_path,
298 const int flags) {
299 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
301 if (base::DirectoryExists(base::FilePath(file_path)))
302 return std::make_pair(-1, base::File::FILE_ERROR_NOT_A_FILE);
303 int file_descriptor = open(file_path, flags);
304 if (file_descriptor >= 0)
305 return std::make_pair(file_descriptor, base::File::FILE_OK);
306 if (errno == ENOENT)
307 return std::make_pair(file_descriptor, base::File::FILE_ERROR_NOT_FOUND);
308 return std::make_pair(file_descriptor, base::File::FILE_ERROR_FAILED);
311 // Closes |file_descriptor| on file thread.
312 void CloseFileDescriptor(const int file_descriptor) {
313 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
315 IGNORE_EINTR(close(file_descriptor));
318 // Deletes a temporary file |file_path|.
319 void DeleteTemporaryFile(const base::FilePath& file_path) {
320 content::BrowserThread::PostBlockingPoolTask(
321 FROM_HERE, base::Bind(base::IgnoreResult(base::DeleteFile), file_path,
322 false /* not recursive*/));
325 // A fake callback to be passed as CopyFileProgressCallback.
326 void FakeCopyFileProgressCallback(int64 size) {
329 } // namespace
331 MTPDeviceDelegateImplLinux::PendingTaskInfo::PendingTaskInfo(
332 const base::FilePath& path,
333 content::BrowserThread::ID thread_id,
334 const tracked_objects::Location& location,
335 const base::Closure& task)
336 : path(path),
337 thread_id(thread_id),
338 location(location),
339 task(task) {
342 MTPDeviceDelegateImplLinux::PendingTaskInfo::~PendingTaskInfo() {
345 // Represents a file on the MTP device.
346 // Lives on the IO thread.
347 class MTPDeviceDelegateImplLinux::MTPFileNode {
348 public:
349 MTPFileNode(uint32 file_id,
350 const std::string& file_name,
351 MTPFileNode* parent,
352 FileIdToMTPFileNodeMap* file_id_to_node_map);
353 ~MTPFileNode();
355 const MTPFileNode* GetChild(const std::string& name) const;
357 void EnsureChildExists(const std::string& name, uint32 id);
359 // Clears all the children, except those in |children_to_keep|.
360 void ClearNonexistentChildren(
361 const std::set<std::string>& children_to_keep);
363 bool DeleteChild(uint32 file_id);
365 bool HasChildren() const;
367 uint32 file_id() const { return file_id_; }
368 const std::string& file_name() const { return file_name_; }
369 MTPFileNode* parent() { return parent_; }
371 private:
372 // Container for holding a node's children.
373 typedef base::ScopedPtrHashMap<std::string, MTPFileNode> ChildNodes;
375 const uint32 file_id_;
376 const std::string file_name_;
378 ChildNodes children_;
379 MTPFileNode* const parent_;
380 FileIdToMTPFileNodeMap* file_id_to_node_map_;
382 DISALLOW_COPY_AND_ASSIGN(MTPFileNode);
385 MTPDeviceDelegateImplLinux::MTPFileNode::MTPFileNode(
386 uint32 file_id,
387 const std::string& file_name,
388 MTPFileNode* parent,
389 FileIdToMTPFileNodeMap* file_id_to_node_map)
390 : file_id_(file_id),
391 file_name_(file_name),
392 parent_(parent),
393 file_id_to_node_map_(file_id_to_node_map) {
394 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
395 DCHECK(file_id_to_node_map_);
396 DCHECK(!ContainsKey(*file_id_to_node_map_, file_id_));
397 (*file_id_to_node_map_)[file_id_] = this;
400 MTPDeviceDelegateImplLinux::MTPFileNode::~MTPFileNode() {
401 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
402 size_t erased = file_id_to_node_map_->erase(file_id_);
403 DCHECK_EQ(1U, erased);
406 const MTPDeviceDelegateImplLinux::MTPFileNode*
407 MTPDeviceDelegateImplLinux::MTPFileNode::GetChild(
408 const std::string& name) const {
409 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
410 return children_.get(name);
413 void MTPDeviceDelegateImplLinux::MTPFileNode::EnsureChildExists(
414 const std::string& name,
415 uint32 id) {
416 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
417 const MTPFileNode* child = GetChild(name);
418 if (child && child->file_id() == id)
419 return;
421 children_.set(
422 name,
423 make_scoped_ptr(new MTPFileNode(id, name, this, file_id_to_node_map_)));
426 void MTPDeviceDelegateImplLinux::MTPFileNode::ClearNonexistentChildren(
427 const std::set<std::string>& children_to_keep) {
428 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
429 std::set<std::string> children_to_erase;
430 for (ChildNodes::const_iterator it = children_.begin();
431 it != children_.end(); ++it) {
432 if (ContainsKey(children_to_keep, it->first))
433 continue;
434 children_to_erase.insert(it->first);
436 for (std::set<std::string>::iterator it = children_to_erase.begin();
437 it != children_to_erase.end(); ++it) {
438 children_.take_and_erase(*it);
442 bool MTPDeviceDelegateImplLinux::MTPFileNode::DeleteChild(uint32 file_id) {
443 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
444 for (ChildNodes::iterator it = children_.begin();
445 it != children_.end(); ++it) {
446 if (it->second->file_id() == file_id) {
447 DCHECK(!it->second->HasChildren());
448 children_.erase(it);
449 return true;
452 return false;
455 bool MTPDeviceDelegateImplLinux::MTPFileNode::HasChildren() const {
456 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
457 return children_.size() > 0;
460 MTPDeviceDelegateImplLinux::MTPDeviceDelegateImplLinux(
461 const std::string& device_location,
462 const bool read_only)
463 : init_state_(UNINITIALIZED),
464 task_in_progress_(false),
465 device_path_(device_location),
466 read_only_(read_only),
467 root_node_(new MTPFileNode(mtpd::kRootFileId,
468 "", // Root node has no name.
469 NULL, // And no parent node.
470 &file_id_to_node_map_)),
471 weak_ptr_factory_(this) {
472 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
473 DCHECK(!device_path_.empty());
474 base::RemoveChars(device_location, kRootPath, &storage_name_);
475 DCHECK(!storage_name_.empty());
478 MTPDeviceDelegateImplLinux::~MTPDeviceDelegateImplLinux() {
479 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
482 void MTPDeviceDelegateImplLinux::GetFileInfo(
483 const base::FilePath& file_path,
484 const GetFileInfoSuccessCallback& success_callback,
485 const ErrorCallback& error_callback) {
486 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
487 DCHECK(!file_path.empty());
489 // If a ReadDirectory operation is in progress, the file info may already be
490 // cached.
491 FileInfoCache::const_iterator it = file_info_cache_.find(file_path);
492 if (it != file_info_cache_.end()) {
493 // TODO(thestig): This code is repeated in several places. Combine them.
494 // e.g. c/b/media_galleries/win/mtp_device_operations_util.cc
495 const storage::DirectoryEntry& cached_file_entry = it->second;
496 base::File::Info info;
497 info.size = cached_file_entry.size;
498 info.is_directory = cached_file_entry.is_directory;
499 info.is_symbolic_link = false;
500 info.last_modified = cached_file_entry.last_modified_time;
501 info.creation_time = base::Time();
503 success_callback.Run(info);
504 return;
506 base::Closure closure =
507 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
508 weak_ptr_factory_.GetWeakPtr(),
509 file_path,
510 success_callback,
511 error_callback);
512 EnsureInitAndRunTask(PendingTaskInfo(file_path,
513 content::BrowserThread::IO,
514 FROM_HERE,
515 closure));
518 void MTPDeviceDelegateImplLinux::ReadDirectory(
519 const base::FilePath& root,
520 const ReadDirectorySuccessCallback& success_callback,
521 const ErrorCallback& error_callback) {
522 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
523 DCHECK(!root.empty());
524 base::Closure closure =
525 base::Bind(&MTPDeviceDelegateImplLinux::ReadDirectoryInternal,
526 weak_ptr_factory_.GetWeakPtr(),
527 root,
528 success_callback,
529 error_callback);
530 EnsureInitAndRunTask(PendingTaskInfo(root,
531 content::BrowserThread::IO,
532 FROM_HERE,
533 closure));
536 void MTPDeviceDelegateImplLinux::CreateSnapshotFile(
537 const base::FilePath& device_file_path,
538 const base::FilePath& local_path,
539 const CreateSnapshotFileSuccessCallback& success_callback,
540 const ErrorCallback& error_callback) {
541 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
542 DCHECK(!device_file_path.empty());
543 DCHECK(!local_path.empty());
544 base::Closure closure =
545 base::Bind(&MTPDeviceDelegateImplLinux::CreateSnapshotFileInternal,
546 weak_ptr_factory_.GetWeakPtr(),
547 device_file_path,
548 local_path,
549 success_callback,
550 error_callback);
551 EnsureInitAndRunTask(PendingTaskInfo(device_file_path,
552 content::BrowserThread::IO,
553 FROM_HERE,
554 closure));
557 bool MTPDeviceDelegateImplLinux::IsStreaming() {
558 return true;
561 void MTPDeviceDelegateImplLinux::ReadBytes(
562 const base::FilePath& device_file_path,
563 const scoped_refptr<net::IOBuffer>& buf,
564 int64 offset,
565 int buf_len,
566 const ReadBytesSuccessCallback& success_callback,
567 const ErrorCallback& error_callback) {
568 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
569 DCHECK(!device_file_path.empty());
570 base::Closure closure =
571 base::Bind(&MTPDeviceDelegateImplLinux::ReadBytesInternal,
572 weak_ptr_factory_.GetWeakPtr(),
573 device_file_path,
574 buf,
575 offset,
576 buf_len,
577 success_callback,
578 error_callback);
579 EnsureInitAndRunTask(PendingTaskInfo(device_file_path,
580 content::BrowserThread::IO,
581 FROM_HERE,
582 closure));
585 bool MTPDeviceDelegateImplLinux::IsReadOnly() const {
586 return read_only_;
589 void MTPDeviceDelegateImplLinux::CopyFileLocal(
590 const base::FilePath& source_file_path,
591 const base::FilePath& device_file_path,
592 const CreateTemporaryFileCallback& create_temporary_file_callback,
593 const CopyFileProgressCallback& progress_callback,
594 const CopyFileLocalSuccessCallback& success_callback,
595 const ErrorCallback& error_callback) {
596 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
597 DCHECK(!source_file_path.empty());
598 DCHECK(!device_file_path.empty());
600 // Create a temporary file for creating a copy of source file on local.
601 content::BrowserThread::PostTaskAndReplyWithResult(
602 content::BrowserThread::FILE, FROM_HERE, create_temporary_file_callback,
603 base::Bind(
604 &MTPDeviceDelegateImplLinux::OnDidCreateTemporaryFileToCopyFileLocal,
605 weak_ptr_factory_.GetWeakPtr(), source_file_path, device_file_path,
606 progress_callback, success_callback, error_callback));
609 void MTPDeviceDelegateImplLinux::MoveFileLocal(
610 const base::FilePath& source_file_path,
611 const base::FilePath& device_file_path,
612 const CreateTemporaryFileCallback& create_temporary_file_callback,
613 const MoveFileLocalSuccessCallback& success_callback,
614 const ErrorCallback& error_callback) {
615 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
616 DCHECK(!source_file_path.empty());
617 DCHECK(!device_file_path.empty());
619 // Get file info to move file on local.
620 const GetFileInfoSuccessCallback success_callback_wrapper = base::Bind(
621 &MTPDeviceDelegateImplLinux::MoveFileLocalInternal,
622 weak_ptr_factory_.GetWeakPtr(), source_file_path, device_file_path,
623 create_temporary_file_callback, success_callback, error_callback);
624 const base::Closure closure =
625 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
626 weak_ptr_factory_.GetWeakPtr(), source_file_path,
627 success_callback_wrapper, error_callback);
628 EnsureInitAndRunTask(PendingTaskInfo(
629 source_file_path, content::BrowserThread::IO, FROM_HERE, closure));
632 void MTPDeviceDelegateImplLinux::CopyFileFromLocal(
633 const base::FilePath& source_file_path,
634 const base::FilePath& device_file_path,
635 const CopyFileFromLocalSuccessCallback& success_callback,
636 const ErrorCallback& error_callback) {
637 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
638 DCHECK(!source_file_path.empty());
639 DCHECK(!device_file_path.empty());
641 // Get file info of destination file path.
642 const GetFileInfoSuccessCallback success_callback_wrapper = base::Bind(
643 &MTPDeviceDelegateImplLinux::OnDidGetDestFileInfoToCopyFileFromLocal,
644 weak_ptr_factory_.GetWeakPtr(), error_callback);
645 const ErrorCallback error_callback_wrapper = base::Bind(
646 &MTPDeviceDelegateImplLinux::OnGetDestFileInfoErrorToCopyFileFromLocal,
647 weak_ptr_factory_.GetWeakPtr(), source_file_path, device_file_path,
648 success_callback, error_callback);
649 const base::Closure closure =
650 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
651 weak_ptr_factory_.GetWeakPtr(), device_file_path,
652 success_callback_wrapper, error_callback_wrapper);
653 EnsureInitAndRunTask(PendingTaskInfo(
654 device_file_path, content::BrowserThread::IO, FROM_HERE, closure));
657 void MTPDeviceDelegateImplLinux::DeleteFile(
658 const base::FilePath& file_path,
659 const DeleteFileSuccessCallback& success_callback,
660 const ErrorCallback& error_callback) {
661 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
662 DCHECK(!file_path.empty());
664 const GetFileInfoSuccessCallback& success_callback_wrapper =
665 base::Bind(&MTPDeviceDelegateImplLinux::DeleteFileInternal,
666 weak_ptr_factory_.GetWeakPtr(), file_path, success_callback,
667 error_callback);
669 const base::Closure closure =
670 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
671 weak_ptr_factory_.GetWeakPtr(), file_path,
672 success_callback_wrapper, error_callback);
673 EnsureInitAndRunTask(PendingTaskInfo(file_path, content::BrowserThread::IO,
674 FROM_HERE, closure));
677 void MTPDeviceDelegateImplLinux::DeleteDirectory(
678 const base::FilePath& file_path,
679 const DeleteDirectorySuccessCallback& success_callback,
680 const ErrorCallback& error_callback) {
681 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
682 DCHECK(!file_path.empty());
684 const GetFileInfoSuccessCallback& success_callback_wrapper =
685 base::Bind(&MTPDeviceDelegateImplLinux::DeleteDirectoryInternal,
686 weak_ptr_factory_.GetWeakPtr(), file_path, success_callback,
687 error_callback);
689 const base::Closure closure =
690 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
691 weak_ptr_factory_.GetWeakPtr(), file_path,
692 success_callback_wrapper, error_callback);
693 EnsureInitAndRunTask(PendingTaskInfo(file_path, content::BrowserThread::IO,
694 FROM_HERE, closure));
697 void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() {
698 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
699 // To cancel all the pending tasks, destroy the MTPDeviceTaskHelper object.
700 content::BrowserThread::PostTask(
701 content::BrowserThread::UI,
702 FROM_HERE,
703 base::Bind(&CloseStorageAndDestroyTaskHelperOnUIThread,
704 storage_name_,
705 read_only_));
706 delete this;
709 void MTPDeviceDelegateImplLinux::GetFileInfoInternal(
710 const base::FilePath& file_path,
711 const GetFileInfoSuccessCallback& success_callback,
712 const ErrorCallback& error_callback) {
713 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
715 uint32 file_id;
716 if (CachedPathToId(file_path, &file_id)) {
717 GetFileInfoSuccessCallback success_callback_wrapper =
718 base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfo,
719 weak_ptr_factory_.GetWeakPtr(),
720 success_callback);
721 ErrorCallback error_callback_wrapper =
722 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
723 weak_ptr_factory_.GetWeakPtr(),
724 error_callback,
725 file_id);
728 base::Closure closure = base::Bind(&GetFileInfoOnUIThread,
729 storage_name_,
730 read_only_,
731 file_id,
732 success_callback_wrapper,
733 error_callback_wrapper);
734 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
735 content::BrowserThread::UI,
736 FROM_HERE,
737 closure));
738 } else {
739 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
741 PendingRequestDone();
744 void MTPDeviceDelegateImplLinux::ReadDirectoryInternal(
745 const base::FilePath& root,
746 const ReadDirectorySuccessCallback& success_callback,
747 const ErrorCallback& error_callback) {
748 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
750 uint32 dir_id;
751 if (CachedPathToId(root, &dir_id)) {
752 GetFileInfoSuccessCallback success_callback_wrapper =
753 base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory,
754 weak_ptr_factory_.GetWeakPtr(),
755 dir_id,
756 success_callback,
757 error_callback);
758 ErrorCallback error_callback_wrapper =
759 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
760 weak_ptr_factory_.GetWeakPtr(),
761 error_callback,
762 dir_id);
763 base::Closure closure = base::Bind(&GetFileInfoOnUIThread,
764 storage_name_,
765 read_only_,
766 dir_id,
767 success_callback_wrapper,
768 error_callback_wrapper);
769 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
770 content::BrowserThread::UI,
771 FROM_HERE,
772 closure));
773 } else {
774 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
776 PendingRequestDone();
779 void MTPDeviceDelegateImplLinux::CreateSnapshotFileInternal(
780 const base::FilePath& device_file_path,
781 const base::FilePath& local_path,
782 const CreateSnapshotFileSuccessCallback& success_callback,
783 const ErrorCallback& error_callback) {
784 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
786 uint32 file_id;
787 if (CachedPathToId(device_file_path, &file_id)) {
788 scoped_ptr<SnapshotRequestInfo> request_info(
789 new SnapshotRequestInfo(file_id,
790 local_path,
791 success_callback,
792 error_callback));
793 GetFileInfoSuccessCallback success_callback_wrapper =
794 base::Bind(
795 &MTPDeviceDelegateImplLinux::OnDidGetFileInfoToCreateSnapshotFile,
796 weak_ptr_factory_.GetWeakPtr(),
797 base::Passed(&request_info));
798 ErrorCallback error_callback_wrapper =
799 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
800 weak_ptr_factory_.GetWeakPtr(),
801 error_callback,
802 file_id);
803 base::Closure closure = base::Bind(&GetFileInfoOnUIThread,
804 storage_name_,
805 read_only_,
806 file_id,
807 success_callback_wrapper,
808 error_callback_wrapper);
809 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
810 content::BrowserThread::UI,
811 FROM_HERE,
812 closure));
813 } else {
814 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
816 PendingRequestDone();
819 void MTPDeviceDelegateImplLinux::ReadBytesInternal(
820 const base::FilePath& device_file_path,
821 net::IOBuffer* buf, int64 offset, int buf_len,
822 const ReadBytesSuccessCallback& success_callback,
823 const ErrorCallback& error_callback) {
824 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
826 uint32 file_id;
827 if (CachedPathToId(device_file_path, &file_id)) {
828 ReadBytesRequest request(
829 file_id, buf, offset, buf_len,
830 base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadBytes,
831 weak_ptr_factory_.GetWeakPtr(),
832 success_callback),
833 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
834 weak_ptr_factory_.GetWeakPtr(),
835 error_callback,
836 file_id));
838 base::Closure closure =
839 base::Bind(&ReadBytesOnUIThread, storage_name_, read_only_, request);
840 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
841 content::BrowserThread::UI,
842 FROM_HERE,
843 closure));
844 } else {
845 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
847 PendingRequestDone();
850 void MTPDeviceDelegateImplLinux::MoveFileLocalInternal(
851 const base::FilePath& source_file_path,
852 const base::FilePath& device_file_path,
853 const CreateTemporaryFileCallback& create_temporary_file_callback,
854 const MoveFileLocalSuccessCallback& success_callback,
855 const ErrorCallback& error_callback,
856 const base::File::Info& source_file_info) {
857 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
859 if (source_file_info.is_directory) {
860 error_callback.Run(base::File::FILE_ERROR_NOT_A_FILE);
861 return;
864 if (source_file_path.DirName() == device_file_path.DirName()) {
865 // If a file is moved in a same directory, rename the file.
866 uint32 file_id;
867 if (CachedPathToId(source_file_path, &file_id)) {
868 const MTPDeviceTaskHelper::RenameObjectSuccessCallback
869 success_callback_wrapper = base::Bind(
870 &MTPDeviceDelegateImplLinux::OnDidMoveFileLocalWithRename,
871 weak_ptr_factory_.GetWeakPtr(), success_callback, file_id);
872 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper =
873 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
874 weak_ptr_factory_.GetWeakPtr(), error_callback, file_id);
875 const base::Closure closure =
876 base::Bind(&RenameObjectOnUIThread, storage_name_, read_only_,
877 file_id, device_file_path.BaseName().value(),
878 success_callback_wrapper, error_callback_wrapper);
879 EnsureInitAndRunTask(PendingTaskInfo(
880 base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
881 } else {
882 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
884 } else {
885 // If a file is moved to a different directory, create a copy to the
886 // destination path, and remove source file.
887 const CopyFileLocalSuccessCallback& success_callback_wrapper =
888 base::Bind(&MTPDeviceDelegateImplLinux::DeleteFileInternal,
889 weak_ptr_factory_.GetWeakPtr(), source_file_path,
890 success_callback, error_callback, source_file_info);
891 CopyFileLocal(source_file_path, device_file_path,
892 create_temporary_file_callback,
893 base::Bind(&FakeCopyFileProgressCallback),
894 success_callback_wrapper, error_callback);
898 void MTPDeviceDelegateImplLinux::OnDidOpenFDToCopyFileFromLocal(
899 const base::FilePath& device_file_path,
900 const CopyFileFromLocalSuccessCallback& success_callback,
901 const ErrorCallback& error_callback,
902 const std::pair<int, base::File::Error>& open_fd_result) {
903 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
905 if (open_fd_result.second != base::File::FILE_OK) {
906 error_callback.Run(open_fd_result.second);
907 return;
910 const int source_file_descriptor = open_fd_result.first;
911 uint32 parent_id;
912 if (CachedPathToId(device_file_path.DirName(), &parent_id)) {
913 CopyFileFromLocalSuccessCallback success_callback_wrapper =
914 base::Bind(&MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocal,
915 weak_ptr_factory_.GetWeakPtr(), success_callback,
916 source_file_descriptor);
918 ErrorCallback error_callback_wrapper = base::Bind(
919 &MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError,
920 weak_ptr_factory_.GetWeakPtr(), error_callback, source_file_descriptor);
922 base::Closure closure = base::Bind(&CopyFileFromLocalOnUIThread,
923 storage_name_,
924 read_only_,
925 source_file_descriptor,
926 parent_id,
927 device_file_path.BaseName().value(),
928 success_callback_wrapper,
929 error_callback_wrapper);
931 EnsureInitAndRunTask(PendingTaskInfo(
932 base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
933 } else {
934 HandleCopyFileFromLocalError(error_callback, source_file_descriptor,
935 base::File::FILE_ERROR_NOT_FOUND);
939 void MTPDeviceDelegateImplLinux::DeleteFileInternal(
940 const base::FilePath& file_path,
941 const DeleteFileSuccessCallback& success_callback,
942 const ErrorCallback& error_callback,
943 const base::File::Info& file_info) {
944 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
946 if (file_info.is_directory) {
947 error_callback.Run(base::File::FILE_ERROR_NOT_A_FILE);
948 } else {
949 uint32 file_id;
950 if (CachedPathToId(file_path, &file_id))
951 RunDeleteObjectOnUIThread(file_id, success_callback, error_callback);
952 else
953 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
957 void MTPDeviceDelegateImplLinux::DeleteDirectoryInternal(
958 const base::FilePath& file_path,
959 const DeleteDirectorySuccessCallback& success_callback,
960 const ErrorCallback& error_callback,
961 const base::File::Info& file_info) {
962 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
964 if (!file_info.is_directory) {
965 error_callback.Run(base::File::FILE_ERROR_NOT_A_DIRECTORY);
966 return;
969 uint32 directory_id;
970 if (!CachedPathToId(file_path, &directory_id)) {
971 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
972 return;
975 // Checks the cache first. If it has children in cache, the directory cannot
976 // be empty.
977 FileIdToMTPFileNodeMap::const_iterator it =
978 file_id_to_node_map_.find(directory_id);
979 if (it != file_id_to_node_map_.end() && it->second->HasChildren()) {
980 error_callback.Run(base::File::FILE_ERROR_NOT_EMPTY);
981 return;
984 // Since the directory can contain a file even if the cache returns it as
985 // empty, read the directory and confirm the directory is actually empty.
986 const MTPDeviceTaskHelper::ReadDirectorySuccessCallback
987 success_callback_wrapper = base::Bind(
988 &MTPDeviceDelegateImplLinux::OnDidReadDirectoryToDeleteDirectory,
989 weak_ptr_factory_.GetWeakPtr(), directory_id, success_callback,
990 error_callback);
991 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper =
992 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
993 weak_ptr_factory_.GetWeakPtr(), error_callback, directory_id);
994 const base::Closure closure = base::Bind(
995 &ReadDirectoryOnUIThread, storage_name_, read_only_, directory_id,
996 1 /* max_size */, success_callback_wrapper, error_callback_wrapper);
997 EnsureInitAndRunTask(PendingTaskInfo(
998 base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
1001 void MTPDeviceDelegateImplLinux::OnDidReadDirectoryToDeleteDirectory(
1002 const uint32 directory_id,
1003 const DeleteDirectorySuccessCallback& success_callback,
1004 const ErrorCallback& error_callback,
1005 const storage::AsyncFileUtil::EntryList& entries,
1006 const bool has_more) {
1007 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1008 DCHECK(!has_more);
1010 if (entries.size() > 0)
1011 error_callback.Run(base::File::FILE_ERROR_NOT_EMPTY);
1012 else
1013 RunDeleteObjectOnUIThread(directory_id, success_callback, error_callback);
1015 PendingRequestDone();
1018 void MTPDeviceDelegateImplLinux::RunDeleteObjectOnUIThread(
1019 const uint32 object_id,
1020 const DeleteObjectSuccessCallback& success_callback,
1021 const ErrorCallback& error_callback) {
1022 const MTPDeviceTaskHelper::DeleteObjectSuccessCallback
1023 success_callback_wrapper = base::Bind(
1024 &MTPDeviceDelegateImplLinux::OnDidDeleteObject,
1025 weak_ptr_factory_.GetWeakPtr(), object_id, success_callback);
1027 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper =
1028 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeleteFileOrDirectoryError,
1029 weak_ptr_factory_.GetWeakPtr(), error_callback);
1031 const base::Closure closure =
1032 base::Bind(&DeleteObjectOnUIThread, storage_name_, read_only_, object_id,
1033 success_callback_wrapper, error_callback_wrapper);
1034 EnsureInitAndRunTask(PendingTaskInfo(
1035 base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
1038 void MTPDeviceDelegateImplLinux::EnsureInitAndRunTask(
1039 const PendingTaskInfo& task_info) {
1040 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1041 if ((init_state_ == INITIALIZED) && !task_in_progress_) {
1042 RunTask(task_info);
1043 return;
1046 // Only *Internal functions have empty paths. Since they are the continuation
1047 // of the current running task, they get to cut in line.
1048 if (task_info.path.empty())
1049 pending_tasks_.push_front(task_info);
1050 else
1051 pending_tasks_.push_back(task_info);
1053 if (init_state_ == UNINITIALIZED) {
1054 init_state_ = PENDING_INIT;
1055 task_in_progress_ = true;
1056 content::BrowserThread::PostTask(
1057 content::BrowserThread::UI, FROM_HERE,
1058 base::Bind(&OpenStorageOnUIThread, storage_name_, read_only_,
1059 base::Bind(&MTPDeviceDelegateImplLinux::OnInitCompleted,
1060 weak_ptr_factory_.GetWeakPtr())));
1064 void MTPDeviceDelegateImplLinux::RunTask(const PendingTaskInfo& task_info) {
1065 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1066 DCHECK_EQ(INITIALIZED, init_state_);
1067 DCHECK(!task_in_progress_);
1068 task_in_progress_ = true;
1070 bool need_to_check_cache = !task_info.path.empty();
1071 if (need_to_check_cache) {
1072 base::FilePath uncached_path =
1073 NextUncachedPathComponent(task_info.path, task_info.cached_path);
1074 if (!uncached_path.empty()) {
1075 // Save the current task and do a cache lookup first.
1076 pending_tasks_.push_front(task_info);
1077 FillFileCache(uncached_path);
1078 return;
1082 content::BrowserThread::PostTask(task_info.thread_id,
1083 task_info.location,
1084 task_info.task);
1087 void MTPDeviceDelegateImplLinux::WriteDataIntoSnapshotFile(
1088 const base::File::Info& file_info) {
1089 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1090 DCHECK(current_snapshot_request_info_.get());
1091 DCHECK_GT(file_info.size, 0);
1092 DCHECK(task_in_progress_);
1093 SnapshotRequestInfo request_info(
1094 current_snapshot_request_info_->file_id,
1095 current_snapshot_request_info_->snapshot_file_path,
1096 base::Bind(
1097 &MTPDeviceDelegateImplLinux::OnDidWriteDataIntoSnapshotFile,
1098 weak_ptr_factory_.GetWeakPtr()),
1099 base::Bind(
1100 &MTPDeviceDelegateImplLinux::OnWriteDataIntoSnapshotFileError,
1101 weak_ptr_factory_.GetWeakPtr()));
1103 base::Closure task_closure = base::Bind(&WriteDataIntoSnapshotFileOnUIThread,
1104 storage_name_,
1105 read_only_,
1106 request_info,
1107 file_info);
1108 content::BrowserThread::PostTask(content::BrowserThread::UI,
1109 FROM_HERE,
1110 task_closure);
1113 void MTPDeviceDelegateImplLinux::PendingRequestDone() {
1114 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1115 DCHECK(task_in_progress_);
1116 task_in_progress_ = false;
1117 ProcessNextPendingRequest();
1120 void MTPDeviceDelegateImplLinux::ProcessNextPendingRequest() {
1121 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1122 DCHECK(!task_in_progress_);
1123 if (pending_tasks_.empty())
1124 return;
1126 PendingTaskInfo task_info = pending_tasks_.front();
1127 pending_tasks_.pop_front();
1128 RunTask(task_info);
1131 void MTPDeviceDelegateImplLinux::OnInitCompleted(bool succeeded) {
1132 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1133 init_state_ = succeeded ? INITIALIZED : UNINITIALIZED;
1134 PendingRequestDone();
1137 void MTPDeviceDelegateImplLinux::OnDidGetFileInfo(
1138 const GetFileInfoSuccessCallback& success_callback,
1139 const base::File::Info& file_info) {
1140 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1141 success_callback.Run(file_info);
1142 PendingRequestDone();
1145 void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory(
1146 uint32 dir_id,
1147 const ReadDirectorySuccessCallback& success_callback,
1148 const ErrorCallback& error_callback,
1149 const base::File::Info& file_info) {
1150 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1151 DCHECK(task_in_progress_);
1152 if (!file_info.is_directory) {
1153 return HandleDeviceFileError(error_callback,
1154 dir_id,
1155 base::File::FILE_ERROR_NOT_A_DIRECTORY);
1158 base::Closure task_closure = base::Bind(
1159 &ReadDirectoryOnUIThread, storage_name_, read_only_, dir_id,
1160 0 /* max_size */,
1161 base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadDirectory,
1162 weak_ptr_factory_.GetWeakPtr(), dir_id, success_callback),
1163 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
1164 weak_ptr_factory_.GetWeakPtr(), error_callback, dir_id));
1165 content::BrowserThread::PostTask(content::BrowserThread::UI,
1166 FROM_HERE,
1167 task_closure);
1170 void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToCreateSnapshotFile(
1171 scoped_ptr<SnapshotRequestInfo> snapshot_request_info,
1172 const base::File::Info& file_info) {
1173 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1174 DCHECK(!current_snapshot_request_info_.get());
1175 DCHECK(snapshot_request_info.get());
1176 DCHECK(task_in_progress_);
1177 base::File::Error error = base::File::FILE_OK;
1178 if (file_info.is_directory)
1179 error = base::File::FILE_ERROR_NOT_A_FILE;
1180 else if (file_info.size < 0 || file_info.size > kuint32max)
1181 error = base::File::FILE_ERROR_FAILED;
1183 if (error != base::File::FILE_OK)
1184 return HandleDeviceFileError(snapshot_request_info->error_callback,
1185 snapshot_request_info->file_id,
1186 error);
1188 base::File::Info snapshot_file_info(file_info);
1189 // Modify the last modified time to null. This prevents the time stamp
1190 // verfication in LocalFileStreamReader.
1191 snapshot_file_info.last_modified = base::Time();
1193 current_snapshot_request_info_.reset(snapshot_request_info.release());
1194 if (file_info.size == 0) {
1195 // Empty snapshot file.
1196 return OnDidWriteDataIntoSnapshotFile(
1197 snapshot_file_info, current_snapshot_request_info_->snapshot_file_path);
1199 WriteDataIntoSnapshotFile(snapshot_file_info);
1202 void MTPDeviceDelegateImplLinux::OnDidGetDestFileInfoToCopyFileFromLocal(
1203 const ErrorCallback& error_callback,
1204 const base::File::Info& file_info) {
1205 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1207 if (file_info.is_directory)
1208 error_callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
1209 else
1210 error_callback.Run(base::File::FILE_ERROR_FAILED);
1213 void MTPDeviceDelegateImplLinux::OnGetDestFileInfoErrorToCopyFileFromLocal(
1214 const base::FilePath& source_file_path,
1215 const base::FilePath& device_file_path,
1216 const CopyFileFromLocalSuccessCallback& success_callback,
1217 const ErrorCallback& error_callback,
1218 const base::File::Error error) {
1219 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1221 if (error != base::File::FILE_ERROR_NOT_FOUND) {
1222 error_callback.Run(error);
1223 return;
1226 content::BrowserThread::PostTaskAndReplyWithResult(
1227 content::BrowserThread::FILE, FROM_HERE,
1228 base::Bind(&OpenFileDescriptor, source_file_path.value().c_str(),
1229 O_RDONLY),
1230 base::Bind(&MTPDeviceDelegateImplLinux::OnDidOpenFDToCopyFileFromLocal,
1231 weak_ptr_factory_.GetWeakPtr(), device_file_path,
1232 success_callback, error_callback));
1235 void MTPDeviceDelegateImplLinux::OnDidReadDirectory(
1236 uint32 dir_id,
1237 const ReadDirectorySuccessCallback& success_callback,
1238 const storage::AsyncFileUtil::EntryList& file_list,
1239 bool has_more) {
1240 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1242 FileIdToMTPFileNodeMap::iterator it = file_id_to_node_map_.find(dir_id);
1243 DCHECK(it != file_id_to_node_map_.end());
1244 MTPFileNode* dir_node = it->second;
1246 // Traverse the MTPFileNode tree to reconstuct the full path for |dir_id|.
1247 std::deque<std::string> dir_path_parts;
1248 MTPFileNode* parent_node = dir_node;
1249 while (parent_node->parent()) {
1250 dir_path_parts.push_front(parent_node->file_name());
1251 parent_node = parent_node->parent();
1253 base::FilePath dir_path = device_path_;
1254 for (size_t i = 0; i < dir_path_parts.size(); ++i)
1255 dir_path = dir_path.Append(dir_path_parts[i]);
1257 storage::AsyncFileUtil::EntryList normalized_file_list;
1258 for (size_t i = 0; i < file_list.size(); ++i) {
1259 normalized_file_list.push_back(file_list[i]);
1260 storage::DirectoryEntry& entry = normalized_file_list.back();
1262 // |entry.name| has the file id encoded in it. Decode here.
1263 size_t separator_idx = entry.name.find_last_of(',');
1264 DCHECK_NE(std::string::npos, separator_idx);
1265 std::string file_id_str = entry.name.substr(separator_idx);
1266 file_id_str = file_id_str.substr(1); // Get rid of the comma.
1267 uint32 file_id = 0;
1268 bool ret = base::StringToUint(file_id_str, &file_id);
1269 DCHECK(ret);
1270 entry.name = entry.name.substr(0, separator_idx);
1272 // Refresh the in memory tree.
1273 dir_node->EnsureChildExists(entry.name, file_id);
1274 child_nodes_seen_.insert(entry.name);
1276 // Add to |file_info_cache_|.
1277 file_info_cache_[dir_path.Append(entry.name)] = entry;
1280 success_callback.Run(normalized_file_list, has_more);
1281 if (has_more)
1282 return; // Wait to be called again.
1284 // Last call, finish book keeping and continue with the next request.
1285 dir_node->ClearNonexistentChildren(child_nodes_seen_);
1286 child_nodes_seen_.clear();
1287 file_info_cache_.clear();
1289 PendingRequestDone();
1292 void MTPDeviceDelegateImplLinux::OnDidWriteDataIntoSnapshotFile(
1293 const base::File::Info& file_info,
1294 const base::FilePath& snapshot_file_path) {
1295 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1296 DCHECK(current_snapshot_request_info_.get());
1297 current_snapshot_request_info_->success_callback.Run(
1298 file_info, snapshot_file_path);
1299 current_snapshot_request_info_.reset();
1300 PendingRequestDone();
1303 void MTPDeviceDelegateImplLinux::OnWriteDataIntoSnapshotFileError(
1304 base::File::Error error) {
1305 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1306 DCHECK(current_snapshot_request_info_.get());
1307 current_snapshot_request_info_->error_callback.Run(error);
1308 current_snapshot_request_info_.reset();
1309 PendingRequestDone();
1312 void MTPDeviceDelegateImplLinux::OnDidReadBytes(
1313 const ReadBytesSuccessCallback& success_callback,
1314 const base::File::Info& file_info, int bytes_read) {
1315 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1316 success_callback.Run(file_info, bytes_read);
1317 PendingRequestDone();
1320 void MTPDeviceDelegateImplLinux::OnDidFillFileCache(
1321 const base::FilePath& path,
1322 const storage::AsyncFileUtil::EntryList& /* file_list */,
1323 bool has_more) {
1324 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1325 DCHECK(path.IsParent(pending_tasks_.front().path));
1326 if (has_more)
1327 return; // Wait until all entries have been read.
1328 pending_tasks_.front().cached_path = path;
1331 void MTPDeviceDelegateImplLinux::OnFillFileCacheFailed(
1332 base::File::Error /* error */) {
1333 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1334 // When filling the cache fails for the task at the front of the queue, clear
1335 // the path of the task so it will not try to do any more caching. Instead,
1336 // the task will just run and fail the CachedPathToId() lookup.
1337 pending_tasks_.front().path.clear();
1340 void MTPDeviceDelegateImplLinux::OnDidCreateTemporaryFileToCopyFileLocal(
1341 const base::FilePath& source_file_path,
1342 const base::FilePath& device_file_path,
1343 const CopyFileProgressCallback& progress_callback,
1344 const CopyFileLocalSuccessCallback& success_callback,
1345 const ErrorCallback& error_callback,
1346 const base::FilePath& temporary_file_path) {
1347 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1349 if (temporary_file_path.empty()) {
1350 error_callback.Run(base::File::FILE_ERROR_FAILED);
1351 return;
1354 CreateSnapshotFile(
1355 source_file_path, temporary_file_path,
1356 base::Bind(
1357 &MTPDeviceDelegateImplLinux::OnDidCreateSnapshotFileOfCopyFileLocal,
1358 weak_ptr_factory_.GetWeakPtr(), device_file_path, progress_callback,
1359 success_callback, error_callback),
1360 base::Bind(&MTPDeviceDelegateImplLinux::HandleCopyFileLocalError,
1361 weak_ptr_factory_.GetWeakPtr(), error_callback,
1362 temporary_file_path));
1365 void MTPDeviceDelegateImplLinux::OnDidCreateSnapshotFileOfCopyFileLocal(
1366 const base::FilePath& device_file_path,
1367 const CopyFileProgressCallback& progress_callback,
1368 const CopyFileLocalSuccessCallback& success_callback,
1369 const ErrorCallback& error_callback,
1370 const base::File::Info& file_info,
1371 const base::FilePath& temporary_file_path) {
1372 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1374 // Consider that half of copy is completed by creating a temporary file.
1375 progress_callback.Run(file_info.size / 2);
1377 CopyFileFromLocal(
1378 temporary_file_path, device_file_path,
1379 base::Bind(
1380 &MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocalOfCopyFileLocal,
1381 weak_ptr_factory_.GetWeakPtr(), success_callback,
1382 temporary_file_path),
1383 base::Bind(&MTPDeviceDelegateImplLinux::HandleCopyFileLocalError,
1384 weak_ptr_factory_.GetWeakPtr(), error_callback,
1385 temporary_file_path));
1388 void MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocalOfCopyFileLocal(
1389 const CopyFileFromLocalSuccessCallback success_callback,
1390 const base::FilePath& temporary_file_path) {
1391 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1393 DeleteTemporaryFile(temporary_file_path);
1394 success_callback.Run();
1397 void MTPDeviceDelegateImplLinux::OnDidMoveFileLocalWithRename(
1398 const MoveFileLocalSuccessCallback& success_callback,
1399 const uint32 file_id) {
1400 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1402 EvictCachedPathToId(file_id);
1403 success_callback.Run();
1404 PendingRequestDone();
1407 void MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocal(
1408 const CopyFileFromLocalSuccessCallback& success_callback,
1409 const int source_file_descriptor) {
1410 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1412 const base::Closure closure = base::Bind(&CloseFileDescriptor,
1413 source_file_descriptor);
1415 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1416 closure);
1418 success_callback.Run();
1419 PendingRequestDone();
1422 void MTPDeviceDelegateImplLinux::HandleCopyFileLocalError(
1423 const ErrorCallback& error_callback,
1424 const base::FilePath& temporary_file_path,
1425 const base::File::Error error) {
1426 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1428 DeleteTemporaryFile(temporary_file_path);
1429 error_callback.Run(error);
1432 void MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError(
1433 const ErrorCallback& error_callback,
1434 const int source_file_descriptor,
1435 base::File::Error error) {
1436 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1438 const base::Closure closure = base::Bind(&CloseFileDescriptor,
1439 source_file_descriptor);
1441 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1442 closure);
1444 error_callback.Run(error);
1445 PendingRequestDone();
1448 void MTPDeviceDelegateImplLinux::OnDidDeleteObject(
1449 const uint32 object_id,
1450 const DeleteObjectSuccessCallback success_callback) {
1451 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1453 EvictCachedPathToId(object_id);
1454 success_callback.Run();
1455 PendingRequestDone();
1458 void MTPDeviceDelegateImplLinux::HandleDeleteFileOrDirectoryError(
1459 const ErrorCallback& error_callback,
1460 base::File::Error error) {
1461 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1463 error_callback.Run(error);
1464 PendingRequestDone();
1467 void MTPDeviceDelegateImplLinux::HandleDeviceFileError(
1468 const ErrorCallback& error_callback,
1469 uint32 file_id,
1470 base::File::Error error) {
1471 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1473 EvictCachedPathToId(file_id);
1474 error_callback.Run(error);
1475 PendingRequestDone();
1478 base::FilePath MTPDeviceDelegateImplLinux::NextUncachedPathComponent(
1479 const base::FilePath& path,
1480 const base::FilePath& cached_path) const {
1481 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1482 DCHECK(cached_path.empty() || cached_path.IsParent(path));
1484 base::FilePath uncached_path;
1485 std::string device_relpath = GetDeviceRelativePath(device_path_, path);
1486 if (!device_relpath.empty() && device_relpath != kRootPath) {
1487 uncached_path = device_path_;
1488 std::vector<std::string> device_relpath_components;
1489 base::SplitString(device_relpath, '/', &device_relpath_components);
1490 DCHECK(!device_relpath_components.empty());
1491 bool all_components_cached = true;
1492 const MTPFileNode* current_node = root_node_.get();
1493 for (size_t i = 0; i < device_relpath_components.size(); ++i) {
1494 current_node = current_node->GetChild(device_relpath_components[i]);
1495 if (!current_node) {
1496 // With a cache miss, check if it is a genuine failure. If so, pretend
1497 // the entire |path| is cached, so there is no further attempt to do
1498 // more caching. The actual operation will then fail.
1499 all_components_cached =
1500 !cached_path.empty() && (uncached_path == cached_path);
1501 break;
1503 uncached_path = uncached_path.Append(device_relpath_components[i]);
1505 if (all_components_cached)
1506 uncached_path.clear();
1508 return uncached_path;
1511 void MTPDeviceDelegateImplLinux::FillFileCache(
1512 const base::FilePath& uncached_path) {
1513 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1514 DCHECK(task_in_progress_);
1516 ReadDirectorySuccessCallback success_callback =
1517 base::Bind(&MTPDeviceDelegateImplLinux::OnDidFillFileCache,
1518 weak_ptr_factory_.GetWeakPtr(),
1519 uncached_path);
1520 ErrorCallback error_callback =
1521 base::Bind(&MTPDeviceDelegateImplLinux::OnFillFileCacheFailed,
1522 weak_ptr_factory_.GetWeakPtr());
1523 ReadDirectoryInternal(uncached_path, success_callback, error_callback);
1527 bool MTPDeviceDelegateImplLinux::CachedPathToId(const base::FilePath& path,
1528 uint32* id) const {
1529 DCHECK(id);
1531 std::string device_relpath = GetDeviceRelativePath(device_path_, path);
1532 if (device_relpath.empty())
1533 return false;
1534 std::vector<std::string> device_relpath_components;
1535 if (device_relpath != kRootPath)
1536 base::SplitString(device_relpath, '/', &device_relpath_components);
1537 const MTPFileNode* current_node = root_node_.get();
1538 for (size_t i = 0; i < device_relpath_components.size(); ++i) {
1539 current_node = current_node->GetChild(device_relpath_components[i]);
1540 if (!current_node)
1541 return false;
1543 *id = current_node->file_id();
1544 return true;
1547 void MTPDeviceDelegateImplLinux::EvictCachedPathToId(const uint32 id) {
1548 FileIdToMTPFileNodeMap::iterator it = file_id_to_node_map_.find(id);
1549 if (it != file_id_to_node_map_.end()) {
1550 DCHECK(!it->second->HasChildren());
1551 MTPFileNode* parent = it->second->parent();
1552 if (parent) {
1553 const bool ret = parent->DeleteChild(id);
1554 DCHECK(ret);
1559 void CreateMTPDeviceAsyncDelegate(
1560 const std::string& device_location,
1561 const bool read_only,
1562 const CreateMTPDeviceAsyncDelegateCallback& callback) {
1563 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1564 callback.Run(new MTPDeviceDelegateImplLinux(device_location, read_only));