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"
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"
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
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());
41 if (registered_dev_path
== file_path
) {
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();
53 // Returns the MTPDeviceTaskHelper object associated with the MTP device
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(
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
,
81 const MTPDeviceTaskHelper::OpenStorageCallback
& reply_callback
) {
82 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
83 MTPDeviceTaskHelper
* task_helper
=
84 GetDeviceTaskHelperForStorage(storage_name
, read_only
);
87 MTPDeviceTaskHelperMapService::GetInstance()->CreateDeviceTaskHelper(
88 storage_name
, read_only
);
90 task_helper
->OpenStorage(storage_name
, read_only
, reply_callback
);
93 // Creates |directory_name| on |parent_id|.
95 // |storage_name| specifies the name of the storage device.
96 // |read_only| specifies the mode of the storage device.
97 // |parent_id| is an object id of the parent directory.
98 // |directory_name| is name of the new directory.
99 // |success_callback| is called when the directory is created successfully.
100 // |error_callback| is called when it fails to create a directory.
101 // |success_callback| and |error_callback| runs on the IO thread.
102 void CreateDirectoryOnUIThread(
103 const std::string
& storage_name
,
104 const bool read_only
,
105 const uint32 parent_id
,
106 const std::string
& directory_name
,
107 const MTPDeviceTaskHelper::CreateDirectorySuccessCallback
& success_callback
,
108 const MTPDeviceTaskHelper::ErrorCallback
& error_callback
) {
109 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
110 MTPDeviceTaskHelper
* task_helper
=
111 GetDeviceTaskHelperForStorage(storage_name
, read_only
);
114 task_helper
->CreateDirectory(parent_id
, directory_name
, success_callback
,
118 // Enumerates the |dir_id| directory file entries.
120 // Called on the UI thread to dispatch the request to the
121 // MediaTransferProtocolManager.
123 // |storage_name| specifies the name of the storage device.
124 // |read_only| specifies the mode of the storage device.
125 // |directory_id| is an id of a directory to read.
126 // |max_size| is a maximum size to read. Set 0 not to specify the maximum size.
127 // |success_callback| is called when the ReadDirectory request succeeds.
128 // |error_callback| is called when the ReadDirectory request fails.
129 // |success_callback| and |error_callback| runs on the IO thread.
130 void ReadDirectoryOnUIThread(
131 const std::string
& storage_name
,
132 const bool read_only
,
133 const uint32 directory_id
,
134 const size_t max_size
,
135 const MTPDeviceTaskHelper::ReadDirectorySuccessCallback
& 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
);
142 task_helper
->ReadDirectory(directory_id
, max_size
, success_callback
,
146 // Gets the |file_path| details.
148 // Called on the UI thread to dispatch the request to the
149 // MediaTransferProtocolManager.
151 // |storage_name| specifies the name of the storage device.
152 // |read_only| specifies the mode of the storage device.
153 // |success_callback| is called when the GetFileInfo request succeeds.
154 // |error_callback| is called when the GetFileInfo request fails.
155 // |success_callback| and |error_callback| runs on the IO thread.
156 void GetFileInfoOnUIThread(
157 const std::string
& storage_name
,
158 const bool read_only
,
160 const MTPDeviceTaskHelper::GetFileInfoSuccessCallback
& success_callback
,
161 const MTPDeviceTaskHelper::ErrorCallback
& error_callback
) {
162 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
163 MTPDeviceTaskHelper
* task_helper
=
164 GetDeviceTaskHelperForStorage(storage_name
, read_only
);
167 task_helper
->GetFileInfo(file_id
, success_callback
, error_callback
);
170 // Copies the contents of |device_file_path| to |snapshot_file_path|.
172 // Called on the UI thread to dispatch the request to the
173 // MediaTransferProtocolManager.
175 // |storage_name| specifies the name of the storage device.
176 // |read_only| specifies the mode of the storage device.
177 // |device_file_path| specifies the media device file path.
178 // |snapshot_file_path| specifies the platform path of the snapshot file.
179 // |file_size| specifies the number of bytes that will be written to the
181 // |success_callback| is called when the copy operation succeeds.
182 // |error_callback| is called when the copy operation fails.
183 // |success_callback| and |error_callback| runs on the IO thread.
184 void WriteDataIntoSnapshotFileOnUIThread(
185 const std::string
& storage_name
,
186 const bool read_only
,
187 const SnapshotRequestInfo
& request_info
,
188 const base::File::Info
& snapshot_file_info
) {
189 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
190 MTPDeviceTaskHelper
* task_helper
=
191 GetDeviceTaskHelperForStorage(storage_name
, read_only
);
194 task_helper
->WriteDataIntoSnapshotFile(request_info
, snapshot_file_info
);
197 // Copies the contents of |device_file_path| to |snapshot_file_path|.
199 // Called on the UI thread to dispatch the request to the
200 // MediaTransferProtocolManager.
202 // |storage_name| specifies the name of the storage device.
203 // |read_only| specifies the mode of the storage device.
204 // |request| is a struct containing details about the byte read request.
205 void ReadBytesOnUIThread(
206 const std::string
& storage_name
,
207 const bool read_only
,
208 const MTPDeviceAsyncDelegate::ReadBytesRequest
& request
) {
209 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
210 MTPDeviceTaskHelper
* task_helper
=
211 GetDeviceTaskHelperForStorage(storage_name
, read_only
);
214 task_helper
->ReadBytes(request
);
217 // Renames |object_id| to |new_name|.
219 // |storage_name| specifies the name of the storage device.
220 // |read_only| specifies the mode of the storage device.
221 // |object_id| is an id of object to be renamed.
222 // |new_name| is new name of the object.
223 // |success_callback| is called when the object is renamed successfully.
224 // |error_callback| is called when it fails to rename the object.
225 // |success_callback| and |error_callback| runs on the IO thread.
226 void RenameObjectOnUIThread(
227 const std::string
& storage_name
,
228 const bool read_only
,
229 const uint32 object_id
,
230 const std::string
& new_name
,
231 const MTPDeviceTaskHelper::RenameObjectSuccessCallback
& success_callback
,
232 const MTPDeviceTaskHelper::ErrorCallback
& error_callback
) {
233 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
234 MTPDeviceTaskHelper
* task_helper
=
235 GetDeviceTaskHelperForStorage(storage_name
, read_only
);
238 task_helper
->RenameObject(object_id
, new_name
, success_callback
,
242 // Copies the file |source_file_descriptor| to |file_name| in |parent_id|.
244 // |storage_name| specifies the name of the storage device.
245 // |read_only| specifies the mode of the storage device.
246 // |source_file_descriptor| file descriptor of source file.
247 // |parent_id| object id of a target directory.
248 // |file_name| file name of a target file.
249 // |success_callback| is called when the file is copied successfully.
250 // |error_callback| is called when it fails to copy file.
251 // Since this method does not close the file descriptor, callbacks are
252 // responsible for closing it.
253 void CopyFileFromLocalOnUIThread(
254 const std::string
& storage_name
,
255 const bool read_only
,
256 const int source_file_descriptor
,
257 const uint32 parent_id
,
258 const std::string
& file_name
,
259 const MTPDeviceTaskHelper::CopyFileFromLocalSuccessCallback
&
261 const MTPDeviceTaskHelper::ErrorCallback
& error_callback
) {
262 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
263 MTPDeviceTaskHelper
* task_helper
=
264 GetDeviceTaskHelperForStorage(storage_name
, read_only
);
267 task_helper
->CopyFileFromLocal(storage_name
, source_file_descriptor
,
268 parent_id
, file_name
, success_callback
,
272 // Deletes |object_id|.
274 // Called on the UI thread to dispatch the request to the
275 // MediaTransferProtocolManager.
277 // |storage_name| specifies the name of the storage device.
278 // |read_only| specifies the mode of the storage device.
279 // |object_id| is the object to be deleted.
280 // |success_callback| is called when the object is deleted successfully.
281 // |error_callback| is called when it fails to delete the object.
282 // |success_callback| and |error_callback| runs on the IO thread.
283 void DeleteObjectOnUIThread(
284 const std::string storage_name
,
285 const bool read_only
,
286 const uint32 object_id
,
287 const MTPDeviceTaskHelper::DeleteObjectSuccessCallback success_callback
,
288 const MTPDeviceTaskHelper::ErrorCallback error_callback
) {
289 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
290 MTPDeviceTaskHelper
* task_helper
=
291 GetDeviceTaskHelperForStorage(storage_name
, read_only
);
294 task_helper
->DeleteObject(object_id
, success_callback
, error_callback
);
297 // Closes the device storage specified by the |storage_name| and destroys the
298 // MTPDeviceTaskHelper object associated with the device storage.
300 // Called on the UI thread to dispatch the request to the
301 // MediaTransferProtocolManager.
302 void CloseStorageAndDestroyTaskHelperOnUIThread(
303 const std::string
& storage_name
,
304 const bool read_only
) {
305 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
306 MTPDeviceTaskHelper
* task_helper
=
307 GetDeviceTaskHelperForStorage(storage_name
, read_only
);
310 task_helper
->CloseStorage();
311 MTPDeviceTaskHelperMapService::GetInstance()->DestroyDeviceTaskHelper(
312 storage_name
, read_only
);
315 // Opens |file_path| with |flags|. Returns the result as a pair.
316 // first is file descriptor.
317 // second is base::File::Error. This value is set as following.
318 // - When it succeeds to open a file descriptor, base::File::FILE_OK is set.
319 // - When |file_path| is a directory, base::File::FILE_ERROR_NOT_A_FILE is set.
320 // - When |file_path| does not exist, base::File::FILE_ERROR_NOT_FOUND is set.
321 // - For other error cases, base::File::FILE_ERROR_FAILED is set.
322 std::pair
<int, base::File::Error
> OpenFileDescriptor(const char* file_path
,
324 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
326 if (base::DirectoryExists(base::FilePath(file_path
)))
327 return std::make_pair(-1, base::File::FILE_ERROR_NOT_A_FILE
);
328 int file_descriptor
= open(file_path
, flags
);
329 if (file_descriptor
>= 0)
330 return std::make_pair(file_descriptor
, base::File::FILE_OK
);
332 return std::make_pair(file_descriptor
, base::File::FILE_ERROR_NOT_FOUND
);
333 return std::make_pair(file_descriptor
, base::File::FILE_ERROR_FAILED
);
336 // Closes |file_descriptor| on file thread.
337 void CloseFileDescriptor(const int file_descriptor
) {
338 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
340 IGNORE_EINTR(close(file_descriptor
));
343 // Deletes a temporary file |file_path|.
344 void DeleteTemporaryFile(const base::FilePath
& file_path
) {
345 content::BrowserThread::PostBlockingPoolTask(
346 FROM_HERE
, base::Bind(base::IgnoreResult(base::DeleteFile
), file_path
,
347 false /* not recursive*/));
350 // A fake callback to be passed as CopyFileProgressCallback.
351 void FakeCopyFileProgressCallback(int64 size
) {
356 MTPDeviceDelegateImplLinux::PendingTaskInfo::PendingTaskInfo(
357 const base::FilePath
& path
,
358 content::BrowserThread::ID thread_id
,
359 const tracked_objects::Location
& location
,
360 const base::Closure
& task
)
362 thread_id(thread_id
),
367 MTPDeviceDelegateImplLinux::PendingTaskInfo::~PendingTaskInfo() {
370 // Represents a file on the MTP device.
371 // Lives on the IO thread.
372 class MTPDeviceDelegateImplLinux::MTPFileNode
{
374 MTPFileNode(uint32 file_id
,
375 const std::string
& file_name
,
377 FileIdToMTPFileNodeMap
* file_id_to_node_map
);
380 const MTPFileNode
* GetChild(const std::string
& name
) const;
382 void EnsureChildExists(const std::string
& name
, uint32 id
);
384 // Clears all the children, except those in |children_to_keep|.
385 void ClearNonexistentChildren(
386 const std::set
<std::string
>& children_to_keep
);
388 bool DeleteChild(uint32 file_id
);
390 bool HasChildren() const;
392 uint32
file_id() const { return file_id_
; }
393 const std::string
& file_name() const { return file_name_
; }
394 MTPFileNode
* parent() { return parent_
; }
397 // Container for holding a node's children.
398 typedef base::ScopedPtrHashMap
<std::string
, MTPFileNode
> ChildNodes
;
400 const uint32 file_id_
;
401 const std::string file_name_
;
403 ChildNodes children_
;
404 MTPFileNode
* const parent_
;
405 FileIdToMTPFileNodeMap
* file_id_to_node_map_
;
407 DISALLOW_COPY_AND_ASSIGN(MTPFileNode
);
410 MTPDeviceDelegateImplLinux::MTPFileNode::MTPFileNode(
412 const std::string
& file_name
,
414 FileIdToMTPFileNodeMap
* file_id_to_node_map
)
416 file_name_(file_name
),
418 file_id_to_node_map_(file_id_to_node_map
) {
419 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
420 DCHECK(file_id_to_node_map_
);
421 DCHECK(!ContainsKey(*file_id_to_node_map_
, file_id_
));
422 (*file_id_to_node_map_
)[file_id_
] = this;
425 MTPDeviceDelegateImplLinux::MTPFileNode::~MTPFileNode() {
426 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
427 size_t erased
= file_id_to_node_map_
->erase(file_id_
);
428 DCHECK_EQ(1U, erased
);
431 const MTPDeviceDelegateImplLinux::MTPFileNode
*
432 MTPDeviceDelegateImplLinux::MTPFileNode::GetChild(
433 const std::string
& name
) const {
434 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
435 return children_
.get(name
);
438 void MTPDeviceDelegateImplLinux::MTPFileNode::EnsureChildExists(
439 const std::string
& name
,
441 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
442 const MTPFileNode
* child
= GetChild(name
);
443 if (child
&& child
->file_id() == id
)
448 make_scoped_ptr(new MTPFileNode(id
, name
, this, file_id_to_node_map_
)));
451 void MTPDeviceDelegateImplLinux::MTPFileNode::ClearNonexistentChildren(
452 const std::set
<std::string
>& children_to_keep
) {
453 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
454 std::set
<std::string
> children_to_erase
;
455 for (ChildNodes::const_iterator it
= children_
.begin();
456 it
!= children_
.end(); ++it
) {
457 if (ContainsKey(children_to_keep
, it
->first
))
459 children_to_erase
.insert(it
->first
);
461 for (std::set
<std::string
>::iterator it
= children_to_erase
.begin();
462 it
!= children_to_erase
.end(); ++it
) {
463 children_
.take_and_erase(*it
);
467 bool MTPDeviceDelegateImplLinux::MTPFileNode::DeleteChild(uint32 file_id
) {
468 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
469 for (ChildNodes::iterator it
= children_
.begin();
470 it
!= children_
.end(); ++it
) {
471 if (it
->second
->file_id() == file_id
) {
472 DCHECK(!it
->second
->HasChildren());
480 bool MTPDeviceDelegateImplLinux::MTPFileNode::HasChildren() const {
481 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
482 return children_
.size() > 0;
485 MTPDeviceDelegateImplLinux::MTPDeviceDelegateImplLinux(
486 const std::string
& device_location
,
487 const bool read_only
)
488 : init_state_(UNINITIALIZED
),
489 task_in_progress_(false),
490 device_path_(device_location
),
491 read_only_(read_only
),
492 root_node_(new MTPFileNode(mtpd::kRootFileId
,
493 "", // Root node has no name.
494 NULL
, // And no parent node.
495 &file_id_to_node_map_
)),
496 weak_ptr_factory_(this) {
497 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
498 DCHECK(!device_path_
.empty());
499 base::RemoveChars(device_location
, kRootPath
, &storage_name_
);
500 DCHECK(!storage_name_
.empty());
503 MTPDeviceDelegateImplLinux::~MTPDeviceDelegateImplLinux() {
504 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
507 void MTPDeviceDelegateImplLinux::CreateDirectory(
508 const base::FilePath
& directory_path
,
509 const bool exclusive
,
510 const bool recursive
,
511 const CreateDirectorySuccessCallback
& success_callback
,
512 const ErrorCallback
& error_callback
) {
513 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
514 DCHECK(!directory_path
.empty());
516 // If |directory_path| is not the path in this device, fails with error.
517 if (!device_path_
.IsParent(directory_path
)) {
518 error_callback
.Run(base::File::FILE_ERROR_FAILED
);
522 // Decomposes |directory_path| to components. CreateDirectoryInternal creates
523 // directories by reading |components| from back.
524 std::vector
<base::FilePath
> components
;
526 for (base::FilePath path
= directory_path
; path
!= device_path_
;
527 path
= path
.DirName()) {
528 components
.push_back(path
);
531 components
.push_back(directory_path
);
534 const base::Closure closure
=
535 base::Bind(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal
,
536 weak_ptr_factory_
.GetWeakPtr(), components
, exclusive
,
537 success_callback
, error_callback
);
538 EnsureInitAndRunTask(PendingTaskInfo(
539 directory_path
, content::BrowserThread::IO
, FROM_HERE
, closure
));
542 void MTPDeviceDelegateImplLinux::GetFileInfo(
543 const base::FilePath
& file_path
,
544 const GetFileInfoSuccessCallback
& success_callback
,
545 const ErrorCallback
& error_callback
) {
546 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
547 DCHECK(!file_path
.empty());
549 // If a ReadDirectory operation is in progress, the file info may already be
551 FileInfoCache::const_iterator it
= file_info_cache_
.find(file_path
);
552 if (it
!= file_info_cache_
.end()) {
553 // TODO(thestig): This code is repeated in several places. Combine them.
554 // e.g. c/b/media_galleries/win/mtp_device_operations_util.cc
555 const storage::DirectoryEntry
& cached_file_entry
= it
->second
;
556 base::File::Info info
;
557 info
.size
= cached_file_entry
.size
;
558 info
.is_directory
= cached_file_entry
.is_directory
;
559 info
.is_symbolic_link
= false;
560 info
.last_modified
= cached_file_entry
.last_modified_time
;
561 info
.creation_time
= base::Time();
563 success_callback
.Run(info
);
566 base::Closure closure
=
567 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal
,
568 weak_ptr_factory_
.GetWeakPtr(),
572 EnsureInitAndRunTask(PendingTaskInfo(file_path
,
573 content::BrowserThread::IO
,
578 void MTPDeviceDelegateImplLinux::ReadDirectory(
579 const base::FilePath
& root
,
580 const ReadDirectorySuccessCallback
& success_callback
,
581 const ErrorCallback
& error_callback
) {
582 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
583 DCHECK(!root
.empty());
584 base::Closure closure
=
585 base::Bind(&MTPDeviceDelegateImplLinux::ReadDirectoryInternal
,
586 weak_ptr_factory_
.GetWeakPtr(),
590 EnsureInitAndRunTask(PendingTaskInfo(root
,
591 content::BrowserThread::IO
,
596 void MTPDeviceDelegateImplLinux::CreateSnapshotFile(
597 const base::FilePath
& device_file_path
,
598 const base::FilePath
& local_path
,
599 const CreateSnapshotFileSuccessCallback
& success_callback
,
600 const ErrorCallback
& error_callback
) {
601 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
602 DCHECK(!device_file_path
.empty());
603 DCHECK(!local_path
.empty());
604 base::Closure closure
=
605 base::Bind(&MTPDeviceDelegateImplLinux::CreateSnapshotFileInternal
,
606 weak_ptr_factory_
.GetWeakPtr(),
611 EnsureInitAndRunTask(PendingTaskInfo(device_file_path
,
612 content::BrowserThread::IO
,
617 bool MTPDeviceDelegateImplLinux::IsStreaming() {
621 void MTPDeviceDelegateImplLinux::ReadBytes(
622 const base::FilePath
& device_file_path
,
623 const scoped_refptr
<net::IOBuffer
>& buf
,
626 const ReadBytesSuccessCallback
& success_callback
,
627 const ErrorCallback
& error_callback
) {
628 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
629 DCHECK(!device_file_path
.empty());
630 base::Closure closure
=
631 base::Bind(&MTPDeviceDelegateImplLinux::ReadBytesInternal
,
632 weak_ptr_factory_
.GetWeakPtr(),
639 EnsureInitAndRunTask(PendingTaskInfo(device_file_path
,
640 content::BrowserThread::IO
,
645 bool MTPDeviceDelegateImplLinux::IsReadOnly() const {
649 void MTPDeviceDelegateImplLinux::CopyFileLocal(
650 const base::FilePath
& source_file_path
,
651 const base::FilePath
& device_file_path
,
652 const CreateTemporaryFileCallback
& create_temporary_file_callback
,
653 const CopyFileProgressCallback
& progress_callback
,
654 const CopyFileLocalSuccessCallback
& success_callback
,
655 const ErrorCallback
& error_callback
) {
656 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
657 DCHECK(!source_file_path
.empty());
658 DCHECK(!device_file_path
.empty());
660 // Create a temporary file for creating a copy of source file on local.
661 content::BrowserThread::PostTaskAndReplyWithResult(
662 content::BrowserThread::FILE, FROM_HERE
, create_temporary_file_callback
,
664 &MTPDeviceDelegateImplLinux::OnDidCreateTemporaryFileToCopyFileLocal
,
665 weak_ptr_factory_
.GetWeakPtr(), source_file_path
, device_file_path
,
666 progress_callback
, success_callback
, error_callback
));
669 void MTPDeviceDelegateImplLinux::MoveFileLocal(
670 const base::FilePath
& source_file_path
,
671 const base::FilePath
& device_file_path
,
672 const CreateTemporaryFileCallback
& create_temporary_file_callback
,
673 const MoveFileLocalSuccessCallback
& success_callback
,
674 const ErrorCallback
& error_callback
) {
675 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
676 DCHECK(!source_file_path
.empty());
677 DCHECK(!device_file_path
.empty());
679 // Get file info to move file on local.
680 const GetFileInfoSuccessCallback success_callback_wrapper
= base::Bind(
681 &MTPDeviceDelegateImplLinux::MoveFileLocalInternal
,
682 weak_ptr_factory_
.GetWeakPtr(), source_file_path
, device_file_path
,
683 create_temporary_file_callback
, success_callback
, error_callback
);
684 const base::Closure closure
=
685 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal
,
686 weak_ptr_factory_
.GetWeakPtr(), source_file_path
,
687 success_callback_wrapper
, error_callback
);
688 EnsureInitAndRunTask(PendingTaskInfo(
689 source_file_path
, content::BrowserThread::IO
, FROM_HERE
, closure
));
692 void MTPDeviceDelegateImplLinux::CopyFileFromLocal(
693 const base::FilePath
& source_file_path
,
694 const base::FilePath
& device_file_path
,
695 const CopyFileFromLocalSuccessCallback
& success_callback
,
696 const ErrorCallback
& error_callback
) {
697 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
698 DCHECK(!source_file_path
.empty());
699 DCHECK(!device_file_path
.empty());
701 // Get file info of destination file path.
702 const GetFileInfoSuccessCallback success_callback_wrapper
= base::Bind(
703 &MTPDeviceDelegateImplLinux::OnDidGetDestFileInfoToCopyFileFromLocal
,
704 weak_ptr_factory_
.GetWeakPtr(), error_callback
);
705 const ErrorCallback error_callback_wrapper
= base::Bind(
706 &MTPDeviceDelegateImplLinux::OnGetDestFileInfoErrorToCopyFileFromLocal
,
707 weak_ptr_factory_
.GetWeakPtr(), source_file_path
, device_file_path
,
708 success_callback
, error_callback
);
709 const base::Closure closure
=
710 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal
,
711 weak_ptr_factory_
.GetWeakPtr(), device_file_path
,
712 success_callback_wrapper
, error_callback_wrapper
);
713 EnsureInitAndRunTask(PendingTaskInfo(
714 device_file_path
, content::BrowserThread::IO
, FROM_HERE
, closure
));
717 void MTPDeviceDelegateImplLinux::DeleteFile(
718 const base::FilePath
& file_path
,
719 const DeleteFileSuccessCallback
& success_callback
,
720 const ErrorCallback
& error_callback
) {
721 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
722 DCHECK(!file_path
.empty());
724 const GetFileInfoSuccessCallback
& success_callback_wrapper
=
725 base::Bind(&MTPDeviceDelegateImplLinux::DeleteFileInternal
,
726 weak_ptr_factory_
.GetWeakPtr(), file_path
, success_callback
,
729 const base::Closure closure
=
730 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal
,
731 weak_ptr_factory_
.GetWeakPtr(), file_path
,
732 success_callback_wrapper
, error_callback
);
733 EnsureInitAndRunTask(PendingTaskInfo(file_path
, content::BrowserThread::IO
,
734 FROM_HERE
, closure
));
737 void MTPDeviceDelegateImplLinux::DeleteDirectory(
738 const base::FilePath
& file_path
,
739 const DeleteDirectorySuccessCallback
& success_callback
,
740 const ErrorCallback
& error_callback
) {
741 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
742 DCHECK(!file_path
.empty());
744 const GetFileInfoSuccessCallback
& success_callback_wrapper
=
745 base::Bind(&MTPDeviceDelegateImplLinux::DeleteDirectoryInternal
,
746 weak_ptr_factory_
.GetWeakPtr(), file_path
, success_callback
,
749 const base::Closure closure
=
750 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal
,
751 weak_ptr_factory_
.GetWeakPtr(), file_path
,
752 success_callback_wrapper
, error_callback
);
753 EnsureInitAndRunTask(PendingTaskInfo(file_path
, content::BrowserThread::IO
,
754 FROM_HERE
, closure
));
757 void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() {
758 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
759 // To cancel all the pending tasks, destroy the MTPDeviceTaskHelper object.
760 content::BrowserThread::PostTask(
761 content::BrowserThread::UI
,
763 base::Bind(&CloseStorageAndDestroyTaskHelperOnUIThread
,
769 void MTPDeviceDelegateImplLinux::GetFileInfoInternal(
770 const base::FilePath
& file_path
,
771 const GetFileInfoSuccessCallback
& success_callback
,
772 const ErrorCallback
& error_callback
) {
773 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
776 if (CachedPathToId(file_path
, &file_id
)) {
777 GetFileInfoSuccessCallback success_callback_wrapper
=
778 base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfo
,
779 weak_ptr_factory_
.GetWeakPtr(),
781 ErrorCallback error_callback_wrapper
=
782 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
783 weak_ptr_factory_
.GetWeakPtr(),
788 base::Closure closure
= base::Bind(&GetFileInfoOnUIThread
,
792 success_callback_wrapper
,
793 error_callback_wrapper
);
794 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
795 content::BrowserThread::UI
,
799 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
801 PendingRequestDone();
804 void MTPDeviceDelegateImplLinux::CreateDirectoryInternal(
805 const std::vector
<base::FilePath
>& components
,
806 const bool exclusive
,
807 const CreateDirectorySuccessCallback
& success_callback
,
808 const ErrorCallback
& error_callback
) {
809 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
811 const base::FilePath current_component
= components
.back();
812 std::vector
<base::FilePath
> other_components
= components
;
813 other_components
.pop_back();
815 if (other_components
.empty()) {
816 // Either we reached the last component in the recursive case, or this is
817 // the non-recursive case.
819 if (CachedPathToId(current_component
.DirName(), &parent_id
)) {
820 const base::Closure closure
=
821 base::Bind(&MTPDeviceDelegateImplLinux::CreateSingleDirectory
,
822 weak_ptr_factory_
.GetWeakPtr(), current_component
,
823 exclusive
, success_callback
, error_callback
);
824 EnsureInitAndRunTask(PendingTaskInfo(
825 base::FilePath(), content::BrowserThread::IO
, FROM_HERE
, closure
));
827 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
830 // Ensures that parent directories are created for recursive case.
832 if (CachedPathToId(current_component
, &directory_id
)) {
833 // Parent directory |current_component| already exists, continue creating
835 const base::Closure closure
=
836 base::Bind(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal
,
837 weak_ptr_factory_
.GetWeakPtr(), other_components
,
838 exclusive
, success_callback
, error_callback
);
839 EnsureInitAndRunTask(PendingTaskInfo(
840 base::FilePath(), content::BrowserThread::IO
, FROM_HERE
, closure
));
842 // If parent directory |current_component| does not exist, create it.
843 const CreateDirectorySuccessCallback success_callback_wrapper
=
844 base::Bind(&MTPDeviceDelegateImplLinux::
845 OnDidCreateParentDirectoryToCreateDirectory
,
846 weak_ptr_factory_
.GetWeakPtr(), current_component
,
847 other_components
, exclusive
, success_callback
,
849 // Wraps error callback to return all errors of creating parent
850 // directories as FILE_ERROR_FAILED.
851 const ErrorCallback error_callback_wrapper
=
852 base::Bind(&MTPDeviceDelegateImplLinux::
853 OnCreateParentDirectoryErrorToCreateDirectory
,
854 weak_ptr_factory_
.GetWeakPtr(), error_callback
);
855 const base::Closure closure
=
856 base::Bind(&MTPDeviceDelegateImplLinux::CreateSingleDirectory
,
857 weak_ptr_factory_
.GetWeakPtr(), current_component
,
858 false /* not exclusive */, success_callback_wrapper
,
859 error_callback_wrapper
);
860 EnsureInitAndRunTask(PendingTaskInfo(
861 base::FilePath(), content::BrowserThread::IO
, FROM_HERE
, closure
));
865 PendingRequestDone();
868 void MTPDeviceDelegateImplLinux::ReadDirectoryInternal(
869 const base::FilePath
& root
,
870 const ReadDirectorySuccessCallback
& success_callback
,
871 const ErrorCallback
& error_callback
) {
872 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
875 if (CachedPathToId(root
, &dir_id
)) {
876 GetFileInfoSuccessCallback success_callback_wrapper
=
877 base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory
,
878 weak_ptr_factory_
.GetWeakPtr(),
882 ErrorCallback error_callback_wrapper
=
883 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
884 weak_ptr_factory_
.GetWeakPtr(),
887 base::Closure closure
= base::Bind(&GetFileInfoOnUIThread
,
891 success_callback_wrapper
,
892 error_callback_wrapper
);
893 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
894 content::BrowserThread::UI
,
898 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
900 PendingRequestDone();
903 void MTPDeviceDelegateImplLinux::CreateSnapshotFileInternal(
904 const base::FilePath
& device_file_path
,
905 const base::FilePath
& local_path
,
906 const CreateSnapshotFileSuccessCallback
& success_callback
,
907 const ErrorCallback
& error_callback
) {
908 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
911 if (CachedPathToId(device_file_path
, &file_id
)) {
912 scoped_ptr
<SnapshotRequestInfo
> request_info(
913 new SnapshotRequestInfo(file_id
,
917 GetFileInfoSuccessCallback success_callback_wrapper
=
919 &MTPDeviceDelegateImplLinux::OnDidGetFileInfoToCreateSnapshotFile
,
920 weak_ptr_factory_
.GetWeakPtr(),
921 base::Passed(&request_info
));
922 ErrorCallback error_callback_wrapper
=
923 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
924 weak_ptr_factory_
.GetWeakPtr(),
927 base::Closure closure
= base::Bind(&GetFileInfoOnUIThread
,
931 success_callback_wrapper
,
932 error_callback_wrapper
);
933 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
934 content::BrowserThread::UI
,
938 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
940 PendingRequestDone();
943 void MTPDeviceDelegateImplLinux::ReadBytesInternal(
944 const base::FilePath
& device_file_path
,
945 net::IOBuffer
* buf
, int64 offset
, int buf_len
,
946 const ReadBytesSuccessCallback
& success_callback
,
947 const ErrorCallback
& error_callback
) {
948 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
951 if (CachedPathToId(device_file_path
, &file_id
)) {
952 ReadBytesRequest
request(
953 file_id
, buf
, offset
, buf_len
,
954 base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadBytes
,
955 weak_ptr_factory_
.GetWeakPtr(),
957 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
958 weak_ptr_factory_
.GetWeakPtr(),
962 base::Closure closure
=
963 base::Bind(&ReadBytesOnUIThread
, storage_name_
, read_only_
, request
);
964 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
965 content::BrowserThread::UI
,
969 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
971 PendingRequestDone();
974 void MTPDeviceDelegateImplLinux::MoveFileLocalInternal(
975 const base::FilePath
& source_file_path
,
976 const base::FilePath
& device_file_path
,
977 const CreateTemporaryFileCallback
& create_temporary_file_callback
,
978 const MoveFileLocalSuccessCallback
& success_callback
,
979 const ErrorCallback
& error_callback
,
980 const base::File::Info
& source_file_info
) {
981 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
983 if (source_file_info
.is_directory
) {
984 error_callback
.Run(base::File::FILE_ERROR_NOT_A_FILE
);
988 if (source_file_path
.DirName() == device_file_path
.DirName()) {
989 // If a file is moved in a same directory, rename the file.
991 if (CachedPathToId(source_file_path
, &file_id
)) {
992 const MTPDeviceTaskHelper::RenameObjectSuccessCallback
993 success_callback_wrapper
= base::Bind(
994 &MTPDeviceDelegateImplLinux::OnDidMoveFileLocalWithRename
,
995 weak_ptr_factory_
.GetWeakPtr(), success_callback
, file_id
);
996 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper
=
997 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
998 weak_ptr_factory_
.GetWeakPtr(), error_callback
, file_id
);
999 const base::Closure closure
=
1000 base::Bind(&RenameObjectOnUIThread
, storage_name_
, read_only_
,
1001 file_id
, device_file_path
.BaseName().value(),
1002 success_callback_wrapper
, error_callback_wrapper
);
1003 EnsureInitAndRunTask(PendingTaskInfo(
1004 base::FilePath(), content::BrowserThread::UI
, FROM_HERE
, closure
));
1006 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
1009 // If a file is moved to a different directory, create a copy to the
1010 // destination path, and remove source file.
1011 const CopyFileLocalSuccessCallback
& success_callback_wrapper
=
1012 base::Bind(&MTPDeviceDelegateImplLinux::DeleteFileInternal
,
1013 weak_ptr_factory_
.GetWeakPtr(), source_file_path
,
1014 success_callback
, error_callback
, source_file_info
);
1015 // TODO(yawano): Avoid to call external method from internal code.
1016 CopyFileLocal(source_file_path
, device_file_path
,
1017 create_temporary_file_callback
,
1018 base::Bind(&FakeCopyFileProgressCallback
),
1019 success_callback_wrapper
, error_callback
);
1023 void MTPDeviceDelegateImplLinux::OnDidOpenFDToCopyFileFromLocal(
1024 const base::FilePath
& device_file_path
,
1025 const CopyFileFromLocalSuccessCallback
& success_callback
,
1026 const ErrorCallback
& error_callback
,
1027 const std::pair
<int, base::File::Error
>& open_fd_result
) {
1028 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1030 if (open_fd_result
.second
!= base::File::FILE_OK
) {
1031 error_callback
.Run(open_fd_result
.second
);
1035 const int source_file_descriptor
= open_fd_result
.first
;
1037 if (CachedPathToId(device_file_path
.DirName(), &parent_id
)) {
1038 CopyFileFromLocalSuccessCallback success_callback_wrapper
=
1039 base::Bind(&MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocal
,
1040 weak_ptr_factory_
.GetWeakPtr(), success_callback
,
1041 source_file_descriptor
);
1043 ErrorCallback error_callback_wrapper
= base::Bind(
1044 &MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError
,
1045 weak_ptr_factory_
.GetWeakPtr(), error_callback
, source_file_descriptor
);
1047 base::Closure closure
= base::Bind(&CopyFileFromLocalOnUIThread
,
1050 source_file_descriptor
,
1052 device_file_path
.BaseName().value(),
1053 success_callback_wrapper
,
1054 error_callback_wrapper
);
1056 EnsureInitAndRunTask(PendingTaskInfo(
1057 base::FilePath(), content::BrowserThread::UI
, FROM_HERE
, closure
));
1059 HandleCopyFileFromLocalError(error_callback
, source_file_descriptor
,
1060 base::File::FILE_ERROR_NOT_FOUND
);
1064 void MTPDeviceDelegateImplLinux::DeleteFileInternal(
1065 const base::FilePath
& file_path
,
1066 const DeleteFileSuccessCallback
& success_callback
,
1067 const ErrorCallback
& error_callback
,
1068 const base::File::Info
& file_info
) {
1069 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1071 if (file_info
.is_directory
) {
1072 error_callback
.Run(base::File::FILE_ERROR_NOT_A_FILE
);
1075 if (CachedPathToId(file_path
, &file_id
))
1076 RunDeleteObjectOnUIThread(file_id
, success_callback
, error_callback
);
1078 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
1082 void MTPDeviceDelegateImplLinux::DeleteDirectoryInternal(
1083 const base::FilePath
& file_path
,
1084 const DeleteDirectorySuccessCallback
& success_callback
,
1085 const ErrorCallback
& error_callback
,
1086 const base::File::Info
& file_info
) {
1087 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1089 if (!file_info
.is_directory
) {
1090 error_callback
.Run(base::File::FILE_ERROR_NOT_A_DIRECTORY
);
1094 uint32 directory_id
;
1095 if (!CachedPathToId(file_path
, &directory_id
)) {
1096 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
1100 // Checks the cache first. If it has children in cache, the directory cannot
1102 FileIdToMTPFileNodeMap::const_iterator it
=
1103 file_id_to_node_map_
.find(directory_id
);
1104 if (it
!= file_id_to_node_map_
.end() && it
->second
->HasChildren()) {
1105 error_callback
.Run(base::File::FILE_ERROR_NOT_EMPTY
);
1109 // Since the directory can contain a file even if the cache returns it as
1110 // empty, read the directory and confirm the directory is actually empty.
1111 const MTPDeviceTaskHelper::ReadDirectorySuccessCallback
1112 success_callback_wrapper
= base::Bind(
1113 &MTPDeviceDelegateImplLinux::OnDidReadDirectoryToDeleteDirectory
,
1114 weak_ptr_factory_
.GetWeakPtr(), directory_id
, success_callback
,
1116 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper
=
1117 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
1118 weak_ptr_factory_
.GetWeakPtr(), error_callback
, directory_id
);
1119 const base::Closure closure
= base::Bind(
1120 &ReadDirectoryOnUIThread
, storage_name_
, read_only_
, directory_id
,
1121 1 /* max_size */, success_callback_wrapper
, error_callback_wrapper
);
1122 EnsureInitAndRunTask(PendingTaskInfo(
1123 base::FilePath(), content::BrowserThread::UI
, FROM_HERE
, closure
));
1126 void MTPDeviceDelegateImplLinux::CreateSingleDirectory(
1127 const base::FilePath
& directory_path
,
1128 const bool exclusive
,
1129 const CreateDirectorySuccessCallback
& success_callback
,
1130 const ErrorCallback
& error_callback
) {
1131 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1133 const GetFileInfoSuccessCallback success_callback_wrapper
= base::Bind(
1134 &MTPDeviceDelegateImplLinux::OnPathAlreadyExistsForCreateSingleDirectory
,
1135 weak_ptr_factory_
.GetWeakPtr(), exclusive
, success_callback
,
1137 const ErrorCallback error_callback_wrapper
= base::Bind(
1138 &MTPDeviceDelegateImplLinux::OnPathDoesNotExistForCreateSingleDirectory
,
1139 weak_ptr_factory_
.GetWeakPtr(), directory_path
, success_callback
,
1141 const base::Closure closure
=
1142 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal
,
1143 weak_ptr_factory_
.GetWeakPtr(), directory_path
,
1144 success_callback_wrapper
, error_callback_wrapper
);
1145 EnsureInitAndRunTask(PendingTaskInfo(
1146 base::FilePath(), content::BrowserThread::IO
, FROM_HERE
, closure
));
1147 PendingRequestDone();
1150 void MTPDeviceDelegateImplLinux::OnDidReadDirectoryToCreateDirectory(
1151 const std::vector
<base::FilePath
>& components
,
1152 const bool exclusive
,
1153 const CreateDirectorySuccessCallback
& success_callback
,
1154 const ErrorCallback
& error_callback
,
1155 const storage::AsyncFileUtil::EntryList
& /* file_list */,
1156 const bool has_more
) {
1157 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1160 return; // Wait until all entries have been read.
1162 const base::Closure closure
=
1163 base::Bind(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal
,
1164 weak_ptr_factory_
.GetWeakPtr(), components
, exclusive
,
1165 success_callback
, error_callback
);
1166 EnsureInitAndRunTask(PendingTaskInfo(
1167 base::FilePath(), content::BrowserThread::IO
, FROM_HERE
, closure
));
1170 void MTPDeviceDelegateImplLinux::OnDidReadDirectoryToDeleteDirectory(
1171 const uint32 directory_id
,
1172 const DeleteDirectorySuccessCallback
& success_callback
,
1173 const ErrorCallback
& error_callback
,
1174 const storage::AsyncFileUtil::EntryList
& entries
,
1175 const bool has_more
) {
1176 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1179 if (entries
.size() > 0)
1180 error_callback
.Run(base::File::FILE_ERROR_NOT_EMPTY
);
1182 RunDeleteObjectOnUIThread(directory_id
, success_callback
, error_callback
);
1184 PendingRequestDone();
1187 void MTPDeviceDelegateImplLinux::RunDeleteObjectOnUIThread(
1188 const uint32 object_id
,
1189 const DeleteObjectSuccessCallback
& success_callback
,
1190 const ErrorCallback
& error_callback
) {
1191 const MTPDeviceTaskHelper::DeleteObjectSuccessCallback
1192 success_callback_wrapper
= base::Bind(
1193 &MTPDeviceDelegateImplLinux::OnDidDeleteObject
,
1194 weak_ptr_factory_
.GetWeakPtr(), object_id
, success_callback
);
1196 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper
=
1197 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeleteFileOrDirectoryError
,
1198 weak_ptr_factory_
.GetWeakPtr(), error_callback
);
1200 const base::Closure closure
=
1201 base::Bind(&DeleteObjectOnUIThread
, storage_name_
, read_only_
, object_id
,
1202 success_callback_wrapper
, error_callback_wrapper
);
1203 EnsureInitAndRunTask(PendingTaskInfo(
1204 base::FilePath(), content::BrowserThread::UI
, FROM_HERE
, closure
));
1207 void MTPDeviceDelegateImplLinux::EnsureInitAndRunTask(
1208 const PendingTaskInfo
& task_info
) {
1209 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1210 if ((init_state_
== INITIALIZED
) && !task_in_progress_
) {
1215 // Only *Internal functions have empty paths. Since they are the continuation
1216 // of the current running task, they get to cut in line.
1217 if (task_info
.path
.empty())
1218 pending_tasks_
.push_front(task_info
);
1220 pending_tasks_
.push_back(task_info
);
1222 if (init_state_
== UNINITIALIZED
) {
1223 init_state_
= PENDING_INIT
;
1224 task_in_progress_
= true;
1225 content::BrowserThread::PostTask(
1226 content::BrowserThread::UI
, FROM_HERE
,
1227 base::Bind(&OpenStorageOnUIThread
, storage_name_
, read_only_
,
1228 base::Bind(&MTPDeviceDelegateImplLinux::OnInitCompleted
,
1229 weak_ptr_factory_
.GetWeakPtr())));
1233 void MTPDeviceDelegateImplLinux::RunTask(const PendingTaskInfo
& task_info
) {
1234 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1235 DCHECK_EQ(INITIALIZED
, init_state_
);
1236 DCHECK(!task_in_progress_
);
1237 task_in_progress_
= true;
1239 bool need_to_check_cache
= !task_info
.path
.empty();
1240 if (need_to_check_cache
) {
1241 base::FilePath uncached_path
=
1242 NextUncachedPathComponent(task_info
.path
, task_info
.cached_path
);
1243 if (!uncached_path
.empty()) {
1244 // Save the current task and do a cache lookup first.
1245 pending_tasks_
.push_front(task_info
);
1246 FillFileCache(uncached_path
);
1251 content::BrowserThread::PostTask(task_info
.thread_id
,
1256 void MTPDeviceDelegateImplLinux::WriteDataIntoSnapshotFile(
1257 const base::File::Info
& file_info
) {
1258 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1259 DCHECK(current_snapshot_request_info_
.get());
1260 DCHECK_GT(file_info
.size
, 0);
1261 DCHECK(task_in_progress_
);
1262 SnapshotRequestInfo
request_info(
1263 current_snapshot_request_info_
->file_id
,
1264 current_snapshot_request_info_
->snapshot_file_path
,
1266 &MTPDeviceDelegateImplLinux::OnDidWriteDataIntoSnapshotFile
,
1267 weak_ptr_factory_
.GetWeakPtr()),
1269 &MTPDeviceDelegateImplLinux::OnWriteDataIntoSnapshotFileError
,
1270 weak_ptr_factory_
.GetWeakPtr()));
1272 base::Closure task_closure
= base::Bind(&WriteDataIntoSnapshotFileOnUIThread
,
1277 content::BrowserThread::PostTask(content::BrowserThread::UI
,
1282 void MTPDeviceDelegateImplLinux::PendingRequestDone() {
1283 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1284 DCHECK(task_in_progress_
);
1285 task_in_progress_
= false;
1286 ProcessNextPendingRequest();
1289 void MTPDeviceDelegateImplLinux::ProcessNextPendingRequest() {
1290 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1291 DCHECK(!task_in_progress_
);
1292 if (pending_tasks_
.empty())
1295 PendingTaskInfo task_info
= pending_tasks_
.front();
1296 pending_tasks_
.pop_front();
1300 void MTPDeviceDelegateImplLinux::OnInitCompleted(bool succeeded
) {
1301 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1302 init_state_
= succeeded
? INITIALIZED
: UNINITIALIZED
;
1303 PendingRequestDone();
1306 void MTPDeviceDelegateImplLinux::OnDidGetFileInfo(
1307 const GetFileInfoSuccessCallback
& success_callback
,
1308 const base::File::Info
& file_info
) {
1309 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1310 success_callback
.Run(file_info
);
1311 PendingRequestDone();
1314 void MTPDeviceDelegateImplLinux::OnPathAlreadyExistsForCreateSingleDirectory(
1315 const bool exclusive
,
1316 const CreateDirectorySuccessCallback
& success_callback
,
1317 const ErrorCallback
& error_callback
,
1318 const base::File::Info
& file_info
) {
1319 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1321 if (!file_info
.is_directory
|| exclusive
)
1322 error_callback
.Run(base::File::FILE_ERROR_EXISTS
);
1324 success_callback
.Run();
1327 void MTPDeviceDelegateImplLinux::OnPathDoesNotExistForCreateSingleDirectory(
1328 const base::FilePath
& directory_path
,
1329 const CreateDirectorySuccessCallback
& success_callback
,
1330 const ErrorCallback
& error_callback
,
1331 const base::File::Error error
) {
1332 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1334 if (error
!= base::File::FILE_ERROR_NOT_FOUND
) {
1335 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
1340 if (!CachedPathToId(directory_path
.DirName(), &parent_id
)) {
1341 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
1345 const MTPDeviceTaskHelper::CreateDirectorySuccessCallback
1346 success_callback_wrapper
=
1347 base::Bind(&MTPDeviceDelegateImplLinux::OnDidCreateSingleDirectory
,
1348 weak_ptr_factory_
.GetWeakPtr(), success_callback
);
1349 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper
=
1350 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
1351 weak_ptr_factory_
.GetWeakPtr(), error_callback
, parent_id
);
1352 const base::Closure closure
=
1353 base::Bind(&CreateDirectoryOnUIThread
, storage_name_
, read_only_
,
1354 parent_id
, directory_path
.BaseName().value(),
1355 success_callback_wrapper
, error_callback_wrapper
);
1356 EnsureInitAndRunTask(PendingTaskInfo(
1357 base::FilePath(), content::BrowserThread::UI
, FROM_HERE
, closure
));
1360 void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory(
1362 const ReadDirectorySuccessCallback
& success_callback
,
1363 const ErrorCallback
& error_callback
,
1364 const base::File::Info
& file_info
) {
1365 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1366 DCHECK(task_in_progress_
);
1367 if (!file_info
.is_directory
) {
1368 return HandleDeviceFileError(error_callback
,
1370 base::File::FILE_ERROR_NOT_A_DIRECTORY
);
1373 base::Closure task_closure
= base::Bind(
1374 &ReadDirectoryOnUIThread
, storage_name_
, read_only_
, dir_id
,
1376 base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadDirectory
,
1377 weak_ptr_factory_
.GetWeakPtr(), dir_id
, success_callback
),
1378 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
1379 weak_ptr_factory_
.GetWeakPtr(), error_callback
, dir_id
));
1380 content::BrowserThread::PostTask(content::BrowserThread::UI
,
1385 void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToCreateSnapshotFile(
1386 scoped_ptr
<SnapshotRequestInfo
> snapshot_request_info
,
1387 const base::File::Info
& file_info
) {
1388 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1389 DCHECK(!current_snapshot_request_info_
.get());
1390 DCHECK(snapshot_request_info
.get());
1391 DCHECK(task_in_progress_
);
1392 base::File::Error error
= base::File::FILE_OK
;
1393 if (file_info
.is_directory
)
1394 error
= base::File::FILE_ERROR_NOT_A_FILE
;
1395 else if (file_info
.size
< 0 || file_info
.size
> kuint32max
)
1396 error
= base::File::FILE_ERROR_FAILED
;
1398 if (error
!= base::File::FILE_OK
)
1399 return HandleDeviceFileError(snapshot_request_info
->error_callback
,
1400 snapshot_request_info
->file_id
,
1403 base::File::Info
snapshot_file_info(file_info
);
1404 // Modify the last modified time to null. This prevents the time stamp
1405 // verfication in LocalFileStreamReader.
1406 snapshot_file_info
.last_modified
= base::Time();
1408 current_snapshot_request_info_
.reset(snapshot_request_info
.release());
1409 if (file_info
.size
== 0) {
1410 // Empty snapshot file.
1411 return OnDidWriteDataIntoSnapshotFile(
1412 snapshot_file_info
, current_snapshot_request_info_
->snapshot_file_path
);
1414 WriteDataIntoSnapshotFile(snapshot_file_info
);
1417 void MTPDeviceDelegateImplLinux::OnDidGetDestFileInfoToCopyFileFromLocal(
1418 const ErrorCallback
& error_callback
,
1419 const base::File::Info
& file_info
) {
1420 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1422 if (file_info
.is_directory
)
1423 error_callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
);
1425 error_callback
.Run(base::File::FILE_ERROR_FAILED
);
1428 void MTPDeviceDelegateImplLinux::OnGetDestFileInfoErrorToCopyFileFromLocal(
1429 const base::FilePath
& source_file_path
,
1430 const base::FilePath
& device_file_path
,
1431 const CopyFileFromLocalSuccessCallback
& success_callback
,
1432 const ErrorCallback
& error_callback
,
1433 const base::File::Error error
) {
1434 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1436 if (error
!= base::File::FILE_ERROR_NOT_FOUND
) {
1437 error_callback
.Run(error
);
1441 content::BrowserThread::PostTaskAndReplyWithResult(
1442 content::BrowserThread::FILE, FROM_HERE
,
1443 base::Bind(&OpenFileDescriptor
, source_file_path
.value().c_str(),
1445 base::Bind(&MTPDeviceDelegateImplLinux::OnDidOpenFDToCopyFileFromLocal
,
1446 weak_ptr_factory_
.GetWeakPtr(), device_file_path
,
1447 success_callback
, error_callback
));
1450 void MTPDeviceDelegateImplLinux::OnDidCreateSingleDirectory(
1451 const CreateDirectorySuccessCallback
& success_callback
) {
1452 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1454 success_callback
.Run();
1455 PendingRequestDone();
1458 void MTPDeviceDelegateImplLinux::OnDidCreateParentDirectoryToCreateDirectory(
1459 const base::FilePath
& created_directory
,
1460 const std::vector
<base::FilePath
>& components
,
1461 const bool exclusive
,
1462 const CreateDirectorySuccessCallback
& success_callback
,
1463 const ErrorCallback
& error_callback
) {
1464 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1466 // Calls ReadDirectoryInternal to fill the cache for created directory.
1467 // Calls ReadDirectoryInternal in this method to call it via
1468 // EnsureInitAndRunTask.
1469 const ReadDirectorySuccessCallback
& success_callback_wrapper
= base::Bind(
1470 &MTPDeviceDelegateImplLinux::OnDidReadDirectoryToCreateDirectory
,
1471 weak_ptr_factory_
.GetWeakPtr(), components
, exclusive
, success_callback
,
1473 const base::Closure closure
=
1474 base::Bind(&MTPDeviceDelegateImplLinux::ReadDirectoryInternal
,
1475 weak_ptr_factory_
.GetWeakPtr(), created_directory
.DirName(),
1476 success_callback_wrapper
, error_callback
);
1477 EnsureInitAndRunTask(PendingTaskInfo(
1478 base::FilePath(), content::BrowserThread::IO
, FROM_HERE
, closure
));
1481 void MTPDeviceDelegateImplLinux::OnCreateParentDirectoryErrorToCreateDirectory(
1482 const ErrorCallback
& callback
,
1483 const base::File::Error error
) {
1484 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1486 callback
.Run(base::File::FILE_ERROR_FAILED
);
1489 void MTPDeviceDelegateImplLinux::OnDidReadDirectory(
1491 const ReadDirectorySuccessCallback
& success_callback
,
1492 const storage::AsyncFileUtil::EntryList
& file_list
,
1494 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1496 FileIdToMTPFileNodeMap::iterator it
= file_id_to_node_map_
.find(dir_id
);
1497 DCHECK(it
!= file_id_to_node_map_
.end());
1498 MTPFileNode
* dir_node
= it
->second
;
1500 // Traverse the MTPFileNode tree to reconstuct the full path for |dir_id|.
1501 std::deque
<std::string
> dir_path_parts
;
1502 MTPFileNode
* parent_node
= dir_node
;
1503 while (parent_node
->parent()) {
1504 dir_path_parts
.push_front(parent_node
->file_name());
1505 parent_node
= parent_node
->parent();
1507 base::FilePath dir_path
= device_path_
;
1508 for (size_t i
= 0; i
< dir_path_parts
.size(); ++i
)
1509 dir_path
= dir_path
.Append(dir_path_parts
[i
]);
1511 storage::AsyncFileUtil::EntryList normalized_file_list
;
1512 for (size_t i
= 0; i
< file_list
.size(); ++i
) {
1513 normalized_file_list
.push_back(file_list
[i
]);
1514 storage::DirectoryEntry
& entry
= normalized_file_list
.back();
1516 // |entry.name| has the file id encoded in it. Decode here.
1517 size_t separator_idx
= entry
.name
.find_last_of(',');
1518 DCHECK_NE(std::string::npos
, separator_idx
);
1519 std::string file_id_str
= entry
.name
.substr(separator_idx
);
1520 file_id_str
= file_id_str
.substr(1); // Get rid of the comma.
1522 bool ret
= base::StringToUint(file_id_str
, &file_id
);
1524 entry
.name
= entry
.name
.substr(0, separator_idx
);
1526 // Refresh the in memory tree.
1527 dir_node
->EnsureChildExists(entry
.name
, file_id
);
1528 child_nodes_seen_
.insert(entry
.name
);
1530 // Add to |file_info_cache_|.
1531 file_info_cache_
[dir_path
.Append(entry
.name
)] = entry
;
1534 success_callback
.Run(normalized_file_list
, has_more
);
1536 return; // Wait to be called again.
1538 // Last call, finish book keeping and continue with the next request.
1539 dir_node
->ClearNonexistentChildren(child_nodes_seen_
);
1540 child_nodes_seen_
.clear();
1541 file_info_cache_
.clear();
1543 PendingRequestDone();
1546 void MTPDeviceDelegateImplLinux::OnDidWriteDataIntoSnapshotFile(
1547 const base::File::Info
& file_info
,
1548 const base::FilePath
& snapshot_file_path
) {
1549 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1550 DCHECK(current_snapshot_request_info_
.get());
1551 current_snapshot_request_info_
->success_callback
.Run(
1552 file_info
, snapshot_file_path
);
1553 current_snapshot_request_info_
.reset();
1554 PendingRequestDone();
1557 void MTPDeviceDelegateImplLinux::OnWriteDataIntoSnapshotFileError(
1558 base::File::Error error
) {
1559 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1560 DCHECK(current_snapshot_request_info_
.get());
1561 current_snapshot_request_info_
->error_callback
.Run(error
);
1562 current_snapshot_request_info_
.reset();
1563 PendingRequestDone();
1566 void MTPDeviceDelegateImplLinux::OnDidReadBytes(
1567 const ReadBytesSuccessCallback
& success_callback
,
1568 const base::File::Info
& file_info
, int bytes_read
) {
1569 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1570 success_callback
.Run(file_info
, bytes_read
);
1571 PendingRequestDone();
1574 void MTPDeviceDelegateImplLinux::OnDidFillFileCache(
1575 const base::FilePath
& path
,
1576 const storage::AsyncFileUtil::EntryList
& /* file_list */,
1578 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1579 DCHECK(path
.IsParent(pending_tasks_
.front().path
));
1581 return; // Wait until all entries have been read.
1582 pending_tasks_
.front().cached_path
= path
;
1585 void MTPDeviceDelegateImplLinux::OnFillFileCacheFailed(
1586 base::File::Error
/* error */) {
1587 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1588 // When filling the cache fails for the task at the front of the queue, clear
1589 // the path of the task so it will not try to do any more caching. Instead,
1590 // the task will just run and fail the CachedPathToId() lookup.
1591 pending_tasks_
.front().path
.clear();
1594 void MTPDeviceDelegateImplLinux::OnDidCreateTemporaryFileToCopyFileLocal(
1595 const base::FilePath
& source_file_path
,
1596 const base::FilePath
& device_file_path
,
1597 const CopyFileProgressCallback
& progress_callback
,
1598 const CopyFileLocalSuccessCallback
& success_callback
,
1599 const ErrorCallback
& error_callback
,
1600 const base::FilePath
& temporary_file_path
) {
1601 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1603 if (temporary_file_path
.empty()) {
1604 error_callback
.Run(base::File::FILE_ERROR_FAILED
);
1609 source_file_path
, temporary_file_path
,
1611 &MTPDeviceDelegateImplLinux::OnDidCreateSnapshotFileOfCopyFileLocal
,
1612 weak_ptr_factory_
.GetWeakPtr(), device_file_path
, progress_callback
,
1613 success_callback
, error_callback
),
1614 base::Bind(&MTPDeviceDelegateImplLinux::HandleCopyFileLocalError
,
1615 weak_ptr_factory_
.GetWeakPtr(), error_callback
,
1616 temporary_file_path
));
1619 void MTPDeviceDelegateImplLinux::OnDidCreateSnapshotFileOfCopyFileLocal(
1620 const base::FilePath
& device_file_path
,
1621 const CopyFileProgressCallback
& progress_callback
,
1622 const CopyFileLocalSuccessCallback
& success_callback
,
1623 const ErrorCallback
& error_callback
,
1624 const base::File::Info
& file_info
,
1625 const base::FilePath
& temporary_file_path
) {
1626 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1628 // Consider that half of copy is completed by creating a temporary file.
1629 progress_callback
.Run(file_info
.size
/ 2);
1631 // TODO(yawano): Avoid to call external method from internal code.
1633 temporary_file_path
, device_file_path
,
1635 &MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocalOfCopyFileLocal
,
1636 weak_ptr_factory_
.GetWeakPtr(), success_callback
,
1637 temporary_file_path
),
1638 base::Bind(&MTPDeviceDelegateImplLinux::HandleCopyFileLocalError
,
1639 weak_ptr_factory_
.GetWeakPtr(), error_callback
,
1640 temporary_file_path
));
1643 void MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocalOfCopyFileLocal(
1644 const CopyFileFromLocalSuccessCallback success_callback
,
1645 const base::FilePath
& temporary_file_path
) {
1646 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1648 DeleteTemporaryFile(temporary_file_path
);
1649 success_callback
.Run();
1652 void MTPDeviceDelegateImplLinux::OnDidMoveFileLocalWithRename(
1653 const MoveFileLocalSuccessCallback
& success_callback
,
1654 const uint32 file_id
) {
1655 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1657 EvictCachedPathToId(file_id
);
1658 success_callback
.Run();
1659 PendingRequestDone();
1662 void MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocal(
1663 const CopyFileFromLocalSuccessCallback
& success_callback
,
1664 const int source_file_descriptor
) {
1665 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1667 const base::Closure closure
= base::Bind(&CloseFileDescriptor
,
1668 source_file_descriptor
);
1670 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE
,
1673 success_callback
.Run();
1674 PendingRequestDone();
1677 void MTPDeviceDelegateImplLinux::HandleCopyFileLocalError(
1678 const ErrorCallback
& error_callback
,
1679 const base::FilePath
& temporary_file_path
,
1680 const base::File::Error error
) {
1681 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1683 DeleteTemporaryFile(temporary_file_path
);
1684 error_callback
.Run(error
);
1687 void MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError(
1688 const ErrorCallback
& error_callback
,
1689 const int source_file_descriptor
,
1690 base::File::Error error
) {
1691 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1693 const base::Closure closure
= base::Bind(&CloseFileDescriptor
,
1694 source_file_descriptor
);
1696 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE
,
1699 error_callback
.Run(error
);
1700 PendingRequestDone();
1703 void MTPDeviceDelegateImplLinux::OnDidDeleteObject(
1704 const uint32 object_id
,
1705 const DeleteObjectSuccessCallback success_callback
) {
1706 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1708 EvictCachedPathToId(object_id
);
1709 success_callback
.Run();
1710 PendingRequestDone();
1713 void MTPDeviceDelegateImplLinux::HandleDeleteFileOrDirectoryError(
1714 const ErrorCallback
& error_callback
,
1715 base::File::Error error
) {
1716 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1718 error_callback
.Run(error
);
1719 PendingRequestDone();
1722 void MTPDeviceDelegateImplLinux::HandleDeviceFileError(
1723 const ErrorCallback
& error_callback
,
1725 base::File::Error error
) {
1726 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1728 EvictCachedPathToId(file_id
);
1729 error_callback
.Run(error
);
1730 PendingRequestDone();
1733 base::FilePath
MTPDeviceDelegateImplLinux::NextUncachedPathComponent(
1734 const base::FilePath
& path
,
1735 const base::FilePath
& cached_path
) const {
1736 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1737 DCHECK(cached_path
.empty() || cached_path
.IsParent(path
));
1739 base::FilePath uncached_path
;
1740 std::string device_relpath
= GetDeviceRelativePath(device_path_
, path
);
1741 if (!device_relpath
.empty() && device_relpath
!= kRootPath
) {
1742 uncached_path
= device_path_
;
1743 std::vector
<std::string
> device_relpath_components
;
1744 base::SplitString(device_relpath
, '/', &device_relpath_components
);
1745 DCHECK(!device_relpath_components
.empty());
1746 bool all_components_cached
= true;
1747 const MTPFileNode
* current_node
= root_node_
.get();
1748 for (size_t i
= 0; i
< device_relpath_components
.size(); ++i
) {
1749 current_node
= current_node
->GetChild(device_relpath_components
[i
]);
1750 if (!current_node
) {
1751 // With a cache miss, check if it is a genuine failure. If so, pretend
1752 // the entire |path| is cached, so there is no further attempt to do
1753 // more caching. The actual operation will then fail.
1754 all_components_cached
=
1755 !cached_path
.empty() && (uncached_path
== cached_path
);
1758 uncached_path
= uncached_path
.Append(device_relpath_components
[i
]);
1760 if (all_components_cached
)
1761 uncached_path
.clear();
1763 return uncached_path
;
1766 void MTPDeviceDelegateImplLinux::FillFileCache(
1767 const base::FilePath
& uncached_path
) {
1768 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1769 DCHECK(task_in_progress_
);
1771 ReadDirectorySuccessCallback success_callback
=
1772 base::Bind(&MTPDeviceDelegateImplLinux::OnDidFillFileCache
,
1773 weak_ptr_factory_
.GetWeakPtr(),
1775 ErrorCallback error_callback
=
1776 base::Bind(&MTPDeviceDelegateImplLinux::OnFillFileCacheFailed
,
1777 weak_ptr_factory_
.GetWeakPtr());
1778 ReadDirectoryInternal(uncached_path
, success_callback
, error_callback
);
1782 bool MTPDeviceDelegateImplLinux::CachedPathToId(const base::FilePath
& path
,
1786 std::string device_relpath
= GetDeviceRelativePath(device_path_
, path
);
1787 if (device_relpath
.empty())
1789 std::vector
<std::string
> device_relpath_components
;
1790 if (device_relpath
!= kRootPath
)
1791 base::SplitString(device_relpath
, '/', &device_relpath_components
);
1792 const MTPFileNode
* current_node
= root_node_
.get();
1793 for (size_t i
= 0; i
< device_relpath_components
.size(); ++i
) {
1794 current_node
= current_node
->GetChild(device_relpath_components
[i
]);
1798 *id
= current_node
->file_id();
1802 void MTPDeviceDelegateImplLinux::EvictCachedPathToId(const uint32 id
) {
1803 FileIdToMTPFileNodeMap::iterator it
= file_id_to_node_map_
.find(id
);
1804 if (it
!= file_id_to_node_map_
.end()) {
1805 DCHECK(!it
->second
->HasChildren());
1806 MTPFileNode
* parent
= it
->second
->parent();
1808 const bool ret
= parent
->DeleteChild(id
);
1814 void CreateMTPDeviceAsyncDelegate(
1815 const std::string
& device_location
,
1816 const bool read_only
,
1817 const CreateMTPDeviceAsyncDelegateCallback
& callback
) {
1818 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1819 callback
.Run(new MTPDeviceDelegateImplLinux(device_location
, read_only
));