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
, scoped_ptr
<MTPFileNode
>>
401 const uint32 file_id_
;
402 const std::string file_name_
;
404 ChildNodes children_
;
405 MTPFileNode
* const parent_
;
406 FileIdToMTPFileNodeMap
* file_id_to_node_map_
;
408 DISALLOW_COPY_AND_ASSIGN(MTPFileNode
);
411 MTPDeviceDelegateImplLinux::MTPFileNode::MTPFileNode(
413 const std::string
& file_name
,
415 FileIdToMTPFileNodeMap
* file_id_to_node_map
)
417 file_name_(file_name
),
419 file_id_to_node_map_(file_id_to_node_map
) {
420 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
421 DCHECK(file_id_to_node_map_
);
422 DCHECK(!ContainsKey(*file_id_to_node_map_
, file_id_
));
423 (*file_id_to_node_map_
)[file_id_
] = this;
426 MTPDeviceDelegateImplLinux::MTPFileNode::~MTPFileNode() {
427 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
428 size_t erased
= file_id_to_node_map_
->erase(file_id_
);
429 DCHECK_EQ(1U, erased
);
432 const MTPDeviceDelegateImplLinux::MTPFileNode
*
433 MTPDeviceDelegateImplLinux::MTPFileNode::GetChild(
434 const std::string
& name
) const {
435 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
436 return children_
.get(name
);
439 void MTPDeviceDelegateImplLinux::MTPFileNode::EnsureChildExists(
440 const std::string
& name
,
442 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
443 const MTPFileNode
* child
= GetChild(name
);
444 if (child
&& child
->file_id() == id
)
449 make_scoped_ptr(new MTPFileNode(id
, name
, this, file_id_to_node_map_
)));
452 void MTPDeviceDelegateImplLinux::MTPFileNode::ClearNonexistentChildren(
453 const std::set
<std::string
>& children_to_keep
) {
454 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
455 std::set
<std::string
> children_to_erase
;
456 for (ChildNodes::const_iterator it
= children_
.begin();
457 it
!= children_
.end(); ++it
) {
458 if (ContainsKey(children_to_keep
, it
->first
))
460 children_to_erase
.insert(it
->first
);
462 for (std::set
<std::string
>::iterator it
= children_to_erase
.begin();
463 it
!= children_to_erase
.end(); ++it
) {
464 children_
.take_and_erase(*it
);
468 bool MTPDeviceDelegateImplLinux::MTPFileNode::DeleteChild(uint32 file_id
) {
469 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
470 for (ChildNodes::iterator it
= children_
.begin();
471 it
!= children_
.end(); ++it
) {
472 if (it
->second
->file_id() == file_id
) {
473 DCHECK(!it
->second
->HasChildren());
481 bool MTPDeviceDelegateImplLinux::MTPFileNode::HasChildren() const {
482 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
483 return children_
.size() > 0;
486 MTPDeviceDelegateImplLinux::MTPDeviceDelegateImplLinux(
487 const std::string
& device_location
,
488 const bool read_only
)
489 : init_state_(UNINITIALIZED
),
490 task_in_progress_(false),
491 device_path_(device_location
),
492 read_only_(read_only
),
493 root_node_(new MTPFileNode(mtpd::kRootFileId
,
494 "", // Root node has no name.
495 NULL
, // And no parent node.
496 &file_id_to_node_map_
)),
497 weak_ptr_factory_(this) {
498 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
499 DCHECK(!device_path_
.empty());
500 base::RemoveChars(device_location
, kRootPath
, &storage_name_
);
501 DCHECK(!storage_name_
.empty());
504 MTPDeviceDelegateImplLinux::~MTPDeviceDelegateImplLinux() {
505 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
508 void MTPDeviceDelegateImplLinux::CreateDirectory(
509 const base::FilePath
& directory_path
,
510 const bool exclusive
,
511 const bool recursive
,
512 const CreateDirectorySuccessCallback
& success_callback
,
513 const ErrorCallback
& error_callback
) {
514 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
515 DCHECK(!directory_path
.empty());
517 // If |directory_path| is not the path in this device, fails with error.
518 if (!device_path_
.IsParent(directory_path
)) {
519 error_callback
.Run(base::File::FILE_ERROR_FAILED
);
523 // Decomposes |directory_path| to components. CreateDirectoryInternal creates
524 // directories by reading |components| from back.
525 std::vector
<base::FilePath
> components
;
527 for (base::FilePath path
= directory_path
; path
!= device_path_
;
528 path
= path
.DirName()) {
529 components
.push_back(path
);
532 components
.push_back(directory_path
);
535 const base::Closure closure
=
536 base::Bind(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal
,
537 weak_ptr_factory_
.GetWeakPtr(), components
, exclusive
,
538 success_callback
, error_callback
);
539 EnsureInitAndRunTask(PendingTaskInfo(
540 directory_path
, content::BrowserThread::IO
, FROM_HERE
, closure
));
543 void MTPDeviceDelegateImplLinux::GetFileInfo(
544 const base::FilePath
& file_path
,
545 const GetFileInfoSuccessCallback
& success_callback
,
546 const ErrorCallback
& error_callback
) {
547 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
548 DCHECK(!file_path
.empty());
550 // If a ReadDirectory operation is in progress, the file info may already be
552 FileInfoCache::const_iterator it
= file_info_cache_
.find(file_path
);
553 if (it
!= file_info_cache_
.end()) {
554 // TODO(thestig): This code is repeated in several places. Combine them.
555 // e.g. c/b/media_galleries/win/mtp_device_operations_util.cc
556 const storage::DirectoryEntry
& cached_file_entry
= it
->second
;
557 base::File::Info info
;
558 info
.size
= cached_file_entry
.size
;
559 info
.is_directory
= cached_file_entry
.is_directory
;
560 info
.is_symbolic_link
= false;
561 info
.last_modified
= cached_file_entry
.last_modified_time
;
562 info
.creation_time
= base::Time();
564 success_callback
.Run(info
);
567 base::Closure closure
=
568 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal
,
569 weak_ptr_factory_
.GetWeakPtr(),
573 EnsureInitAndRunTask(PendingTaskInfo(file_path
,
574 content::BrowserThread::IO
,
579 void MTPDeviceDelegateImplLinux::ReadDirectory(
580 const base::FilePath
& root
,
581 const ReadDirectorySuccessCallback
& success_callback
,
582 const ErrorCallback
& error_callback
) {
583 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
584 DCHECK(!root
.empty());
585 base::Closure closure
=
586 base::Bind(&MTPDeviceDelegateImplLinux::ReadDirectoryInternal
,
587 weak_ptr_factory_
.GetWeakPtr(),
591 EnsureInitAndRunTask(PendingTaskInfo(root
,
592 content::BrowserThread::IO
,
597 void MTPDeviceDelegateImplLinux::CreateSnapshotFile(
598 const base::FilePath
& device_file_path
,
599 const base::FilePath
& local_path
,
600 const CreateSnapshotFileSuccessCallback
& success_callback
,
601 const ErrorCallback
& error_callback
) {
602 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
603 DCHECK(!device_file_path
.empty());
604 DCHECK(!local_path
.empty());
605 base::Closure closure
=
606 base::Bind(&MTPDeviceDelegateImplLinux::CreateSnapshotFileInternal
,
607 weak_ptr_factory_
.GetWeakPtr(),
612 EnsureInitAndRunTask(PendingTaskInfo(device_file_path
,
613 content::BrowserThread::IO
,
618 bool MTPDeviceDelegateImplLinux::IsStreaming() {
622 void MTPDeviceDelegateImplLinux::ReadBytes(
623 const base::FilePath
& device_file_path
,
624 const scoped_refptr
<net::IOBuffer
>& buf
,
627 const ReadBytesSuccessCallback
& success_callback
,
628 const ErrorCallback
& error_callback
) {
629 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
630 DCHECK(!device_file_path
.empty());
631 base::Closure closure
=
632 base::Bind(&MTPDeviceDelegateImplLinux::ReadBytesInternal
,
633 weak_ptr_factory_
.GetWeakPtr(),
640 EnsureInitAndRunTask(PendingTaskInfo(device_file_path
,
641 content::BrowserThread::IO
,
646 bool MTPDeviceDelegateImplLinux::IsReadOnly() const {
650 void MTPDeviceDelegateImplLinux::CopyFileLocal(
651 const base::FilePath
& source_file_path
,
652 const base::FilePath
& device_file_path
,
653 const CreateTemporaryFileCallback
& create_temporary_file_callback
,
654 const CopyFileProgressCallback
& progress_callback
,
655 const CopyFileLocalSuccessCallback
& success_callback
,
656 const ErrorCallback
& error_callback
) {
657 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
658 DCHECK(!source_file_path
.empty());
659 DCHECK(!device_file_path
.empty());
661 // Create a temporary file for creating a copy of source file on local.
662 content::BrowserThread::PostTaskAndReplyWithResult(
663 content::BrowserThread::FILE, FROM_HERE
, create_temporary_file_callback
,
665 &MTPDeviceDelegateImplLinux::OnDidCreateTemporaryFileToCopyFileLocal
,
666 weak_ptr_factory_
.GetWeakPtr(), source_file_path
, device_file_path
,
667 progress_callback
, success_callback
, error_callback
));
670 void MTPDeviceDelegateImplLinux::MoveFileLocal(
671 const base::FilePath
& source_file_path
,
672 const base::FilePath
& device_file_path
,
673 const CreateTemporaryFileCallback
& create_temporary_file_callback
,
674 const MoveFileLocalSuccessCallback
& success_callback
,
675 const ErrorCallback
& error_callback
) {
676 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
677 DCHECK(!source_file_path
.empty());
678 DCHECK(!device_file_path
.empty());
680 // Get file info to move file on local.
681 const GetFileInfoSuccessCallback success_callback_wrapper
= base::Bind(
682 &MTPDeviceDelegateImplLinux::MoveFileLocalInternal
,
683 weak_ptr_factory_
.GetWeakPtr(), source_file_path
, device_file_path
,
684 create_temporary_file_callback
, success_callback
, error_callback
);
685 const base::Closure closure
=
686 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal
,
687 weak_ptr_factory_
.GetWeakPtr(), source_file_path
,
688 success_callback_wrapper
, error_callback
);
689 EnsureInitAndRunTask(PendingTaskInfo(
690 source_file_path
, content::BrowserThread::IO
, FROM_HERE
, closure
));
693 void MTPDeviceDelegateImplLinux::CopyFileFromLocal(
694 const base::FilePath
& source_file_path
,
695 const base::FilePath
& device_file_path
,
696 const CopyFileFromLocalSuccessCallback
& success_callback
,
697 const ErrorCallback
& error_callback
) {
698 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
699 DCHECK(!source_file_path
.empty());
700 DCHECK(!device_file_path
.empty());
702 // Get file info of destination file path.
703 const GetFileInfoSuccessCallback success_callback_wrapper
= base::Bind(
704 &MTPDeviceDelegateImplLinux::OnDidGetDestFileInfoToCopyFileFromLocal
,
705 weak_ptr_factory_
.GetWeakPtr(), error_callback
);
706 const ErrorCallback error_callback_wrapper
= base::Bind(
707 &MTPDeviceDelegateImplLinux::OnGetDestFileInfoErrorToCopyFileFromLocal
,
708 weak_ptr_factory_
.GetWeakPtr(), source_file_path
, device_file_path
,
709 success_callback
, error_callback
);
710 const base::Closure closure
=
711 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal
,
712 weak_ptr_factory_
.GetWeakPtr(), device_file_path
,
713 success_callback_wrapper
, error_callback_wrapper
);
714 EnsureInitAndRunTask(PendingTaskInfo(
715 device_file_path
, content::BrowserThread::IO
, FROM_HERE
, closure
));
718 void MTPDeviceDelegateImplLinux::DeleteFile(
719 const base::FilePath
& file_path
,
720 const DeleteFileSuccessCallback
& success_callback
,
721 const ErrorCallback
& error_callback
) {
722 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
723 DCHECK(!file_path
.empty());
725 const GetFileInfoSuccessCallback
& success_callback_wrapper
=
726 base::Bind(&MTPDeviceDelegateImplLinux::DeleteFileInternal
,
727 weak_ptr_factory_
.GetWeakPtr(), file_path
, success_callback
,
730 const base::Closure closure
=
731 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal
,
732 weak_ptr_factory_
.GetWeakPtr(), file_path
,
733 success_callback_wrapper
, error_callback
);
734 EnsureInitAndRunTask(PendingTaskInfo(file_path
, content::BrowserThread::IO
,
735 FROM_HERE
, closure
));
738 void MTPDeviceDelegateImplLinux::DeleteDirectory(
739 const base::FilePath
& file_path
,
740 const DeleteDirectorySuccessCallback
& success_callback
,
741 const ErrorCallback
& error_callback
) {
742 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
743 DCHECK(!file_path
.empty());
745 const GetFileInfoSuccessCallback
& success_callback_wrapper
=
746 base::Bind(&MTPDeviceDelegateImplLinux::DeleteDirectoryInternal
,
747 weak_ptr_factory_
.GetWeakPtr(), file_path
, success_callback
,
750 const base::Closure closure
=
751 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal
,
752 weak_ptr_factory_
.GetWeakPtr(), file_path
,
753 success_callback_wrapper
, error_callback
);
754 EnsureInitAndRunTask(PendingTaskInfo(file_path
, content::BrowserThread::IO
,
755 FROM_HERE
, closure
));
758 void MTPDeviceDelegateImplLinux::AddWatcher(
760 const base::FilePath
& file_path
,
761 const bool recursive
,
762 const storage::WatcherManager::StatusCallback
& callback
,
763 const storage::WatcherManager::NotificationCallback
&
764 notification_callback
) {
766 callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
);
770 const auto it
= subscribers_
.find(file_path
);
771 if (it
!= subscribers_
.end()) {
772 // Adds to existing origin callback map.
773 if (ContainsKey(it
->second
, origin
)) {
774 callback
.Run(base::File::FILE_ERROR_EXISTS
);
778 it
->second
.insert(std::make_pair(origin
, notification_callback
));
780 // Creates new origin callback map.
781 OriginNotificationCallbackMap callback_map
;
782 callback_map
.insert(std::make_pair(origin
, notification_callback
));
783 subscribers_
.insert(std::make_pair(file_path
, callback_map
));
786 callback
.Run(base::File::FILE_OK
);
789 void MTPDeviceDelegateImplLinux::RemoveWatcher(
791 const base::FilePath
& file_path
,
792 const bool recursive
,
793 const storage::WatcherManager::StatusCallback
& callback
) {
795 callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
);
799 const auto it
= subscribers_
.find(file_path
);
800 if (it
== subscribers_
.end()) {
801 callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
805 if (it
->second
.erase(origin
) == 0) {
806 callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
810 if (it
->second
.empty())
811 subscribers_
.erase(it
);
813 callback
.Run(base::File::FILE_OK
);
816 void MTPDeviceDelegateImplLinux::NotifyFileChange(
817 const base::FilePath
& file_path
,
818 const storage::WatcherManager::ChangeType change_type
) {
819 const auto it
= subscribers_
.find(file_path
);
820 if (it
!= subscribers_
.end()) {
821 for (const auto& origin_callback
: it
->second
) {
822 origin_callback
.second
.Run(change_type
);
827 void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() {
828 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
829 // To cancel all the pending tasks, destroy the MTPDeviceTaskHelper object.
830 content::BrowserThread::PostTask(
831 content::BrowserThread::UI
,
833 base::Bind(&CloseStorageAndDestroyTaskHelperOnUIThread
,
839 void MTPDeviceDelegateImplLinux::GetFileInfoInternal(
840 const base::FilePath
& file_path
,
841 const GetFileInfoSuccessCallback
& success_callback
,
842 const ErrorCallback
& error_callback
) {
843 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
846 if (CachedPathToId(file_path
, &file_id
)) {
847 GetFileInfoSuccessCallback success_callback_wrapper
=
848 base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfo
,
849 weak_ptr_factory_
.GetWeakPtr(),
851 ErrorCallback error_callback_wrapper
=
852 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
853 weak_ptr_factory_
.GetWeakPtr(),
858 base::Closure closure
= base::Bind(&GetFileInfoOnUIThread
,
862 success_callback_wrapper
,
863 error_callback_wrapper
);
864 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
865 content::BrowserThread::UI
,
869 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
871 PendingRequestDone();
874 void MTPDeviceDelegateImplLinux::CreateDirectoryInternal(
875 const std::vector
<base::FilePath
>& components
,
876 const bool exclusive
,
877 const CreateDirectorySuccessCallback
& success_callback
,
878 const ErrorCallback
& error_callback
) {
879 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
881 const base::FilePath current_component
= components
.back();
882 std::vector
<base::FilePath
> other_components
= components
;
883 other_components
.pop_back();
885 if (other_components
.empty()) {
886 // Either we reached the last component in the recursive case, or this is
887 // the non-recursive case.
889 if (CachedPathToId(current_component
.DirName(), &parent_id
)) {
890 const base::Closure closure
=
891 base::Bind(&MTPDeviceDelegateImplLinux::CreateSingleDirectory
,
892 weak_ptr_factory_
.GetWeakPtr(), current_component
,
893 exclusive
, success_callback
, error_callback
);
894 EnsureInitAndRunTask(PendingTaskInfo(
895 base::FilePath(), content::BrowserThread::IO
, FROM_HERE
, closure
));
897 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
900 // Ensures that parent directories are created for recursive case.
902 if (CachedPathToId(current_component
, &directory_id
)) {
903 // Parent directory |current_component| already exists, continue creating
905 const base::Closure closure
=
906 base::Bind(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal
,
907 weak_ptr_factory_
.GetWeakPtr(), other_components
,
908 exclusive
, success_callback
, error_callback
);
909 EnsureInitAndRunTask(PendingTaskInfo(
910 base::FilePath(), content::BrowserThread::IO
, FROM_HERE
, closure
));
912 // If parent directory |current_component| does not exist, create it.
913 const CreateDirectorySuccessCallback success_callback_wrapper
=
914 base::Bind(&MTPDeviceDelegateImplLinux::
915 OnDidCreateParentDirectoryToCreateDirectory
,
916 weak_ptr_factory_
.GetWeakPtr(), current_component
,
917 other_components
, exclusive
, success_callback
,
919 // Wraps error callback to return all errors of creating parent
920 // directories as FILE_ERROR_FAILED.
921 const ErrorCallback error_callback_wrapper
=
922 base::Bind(&MTPDeviceDelegateImplLinux::
923 OnCreateParentDirectoryErrorToCreateDirectory
,
924 weak_ptr_factory_
.GetWeakPtr(), error_callback
);
925 const base::Closure closure
=
926 base::Bind(&MTPDeviceDelegateImplLinux::CreateSingleDirectory
,
927 weak_ptr_factory_
.GetWeakPtr(), current_component
,
928 false /* not exclusive */, success_callback_wrapper
,
929 error_callback_wrapper
);
930 EnsureInitAndRunTask(PendingTaskInfo(
931 base::FilePath(), content::BrowserThread::IO
, FROM_HERE
, closure
));
935 PendingRequestDone();
938 void MTPDeviceDelegateImplLinux::ReadDirectoryInternal(
939 const base::FilePath
& root
,
940 const ReadDirectorySuccessCallback
& success_callback
,
941 const ErrorCallback
& error_callback
) {
942 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
945 if (CachedPathToId(root
, &dir_id
)) {
946 GetFileInfoSuccessCallback success_callback_wrapper
=
947 base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory
,
948 weak_ptr_factory_
.GetWeakPtr(),
952 ErrorCallback error_callback_wrapper
=
953 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
954 weak_ptr_factory_
.GetWeakPtr(),
957 base::Closure closure
= base::Bind(&GetFileInfoOnUIThread
,
961 success_callback_wrapper
,
962 error_callback_wrapper
);
963 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
964 content::BrowserThread::UI
,
968 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
970 PendingRequestDone();
973 void MTPDeviceDelegateImplLinux::CreateSnapshotFileInternal(
974 const base::FilePath
& device_file_path
,
975 const base::FilePath
& local_path
,
976 const CreateSnapshotFileSuccessCallback
& success_callback
,
977 const ErrorCallback
& error_callback
) {
978 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
981 if (CachedPathToId(device_file_path
, &file_id
)) {
982 scoped_ptr
<SnapshotRequestInfo
> request_info(
983 new SnapshotRequestInfo(file_id
,
987 GetFileInfoSuccessCallback success_callback_wrapper
=
989 &MTPDeviceDelegateImplLinux::OnDidGetFileInfoToCreateSnapshotFile
,
990 weak_ptr_factory_
.GetWeakPtr(),
991 base::Passed(&request_info
));
992 ErrorCallback error_callback_wrapper
=
993 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
994 weak_ptr_factory_
.GetWeakPtr(),
997 base::Closure closure
= base::Bind(&GetFileInfoOnUIThread
,
1001 success_callback_wrapper
,
1002 error_callback_wrapper
);
1003 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
1004 content::BrowserThread::UI
,
1008 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
1010 PendingRequestDone();
1013 void MTPDeviceDelegateImplLinux::ReadBytesInternal(
1014 const base::FilePath
& device_file_path
,
1015 net::IOBuffer
* buf
, int64 offset
, int buf_len
,
1016 const ReadBytesSuccessCallback
& success_callback
,
1017 const ErrorCallback
& error_callback
) {
1018 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1021 if (CachedPathToId(device_file_path
, &file_id
)) {
1022 ReadBytesRequest
request(
1023 file_id
, buf
, offset
, buf_len
,
1024 base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadBytes
,
1025 weak_ptr_factory_
.GetWeakPtr(),
1027 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
1028 weak_ptr_factory_
.GetWeakPtr(),
1032 base::Closure closure
=
1033 base::Bind(&ReadBytesOnUIThread
, storage_name_
, read_only_
, request
);
1034 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
1035 content::BrowserThread::UI
,
1039 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
1041 PendingRequestDone();
1044 void MTPDeviceDelegateImplLinux::MoveFileLocalInternal(
1045 const base::FilePath
& source_file_path
,
1046 const base::FilePath
& device_file_path
,
1047 const CreateTemporaryFileCallback
& create_temporary_file_callback
,
1048 const MoveFileLocalSuccessCallback
& success_callback
,
1049 const ErrorCallback
& error_callback
,
1050 const base::File::Info
& source_file_info
) {
1051 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1053 if (source_file_info
.is_directory
) {
1054 error_callback
.Run(base::File::FILE_ERROR_NOT_A_FILE
);
1058 if (source_file_path
.DirName() == device_file_path
.DirName()) {
1059 // If a file is moved in a same directory, rename the file.
1061 if (CachedPathToId(source_file_path
, &file_id
)) {
1062 const MTPDeviceTaskHelper::RenameObjectSuccessCallback
1063 success_callback_wrapper
= base::Bind(
1064 &MTPDeviceDelegateImplLinux::OnDidMoveFileLocalWithRename
,
1065 weak_ptr_factory_
.GetWeakPtr(), success_callback
,
1066 source_file_path
, file_id
);
1067 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper
=
1068 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
1069 weak_ptr_factory_
.GetWeakPtr(), error_callback
, file_id
);
1070 const base::Closure closure
=
1071 base::Bind(&RenameObjectOnUIThread
, storage_name_
, read_only_
,
1072 file_id
, device_file_path
.BaseName().value(),
1073 success_callback_wrapper
, error_callback_wrapper
);
1074 EnsureInitAndRunTask(PendingTaskInfo(
1075 base::FilePath(), content::BrowserThread::UI
, FROM_HERE
, closure
));
1077 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
1080 // If a file is moved to a different directory, create a copy to the
1081 // destination path, and remove source file.
1082 const CopyFileLocalSuccessCallback
& success_callback_wrapper
=
1083 base::Bind(&MTPDeviceDelegateImplLinux::DeleteFileInternal
,
1084 weak_ptr_factory_
.GetWeakPtr(), source_file_path
,
1085 success_callback
, error_callback
, source_file_info
);
1086 // TODO(yawano): Avoid to call external method from internal code.
1087 CopyFileLocal(source_file_path
, device_file_path
,
1088 create_temporary_file_callback
,
1089 base::Bind(&FakeCopyFileProgressCallback
),
1090 success_callback_wrapper
, error_callback
);
1094 void MTPDeviceDelegateImplLinux::OnDidOpenFDToCopyFileFromLocal(
1095 const base::FilePath
& device_file_path
,
1096 const CopyFileFromLocalSuccessCallback
& success_callback
,
1097 const ErrorCallback
& error_callback
,
1098 const std::pair
<int, base::File::Error
>& open_fd_result
) {
1099 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1101 if (open_fd_result
.second
!= base::File::FILE_OK
) {
1102 error_callback
.Run(open_fd_result
.second
);
1106 const int source_file_descriptor
= open_fd_result
.first
;
1108 if (CachedPathToId(device_file_path
.DirName(), &parent_id
)) {
1109 CopyFileFromLocalSuccessCallback success_callback_wrapper
=
1110 base::Bind(&MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocal
,
1111 weak_ptr_factory_
.GetWeakPtr(), success_callback
,
1112 device_file_path
, source_file_descriptor
);
1114 ErrorCallback error_callback_wrapper
= base::Bind(
1115 &MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError
,
1116 weak_ptr_factory_
.GetWeakPtr(), error_callback
, source_file_descriptor
);
1118 base::Closure closure
= base::Bind(&CopyFileFromLocalOnUIThread
,
1121 source_file_descriptor
,
1123 device_file_path
.BaseName().value(),
1124 success_callback_wrapper
,
1125 error_callback_wrapper
);
1127 EnsureInitAndRunTask(PendingTaskInfo(
1128 base::FilePath(), content::BrowserThread::UI
, FROM_HERE
, closure
));
1130 HandleCopyFileFromLocalError(error_callback
, source_file_descriptor
,
1131 base::File::FILE_ERROR_NOT_FOUND
);
1135 void MTPDeviceDelegateImplLinux::DeleteFileInternal(
1136 const base::FilePath
& file_path
,
1137 const DeleteFileSuccessCallback
& success_callback
,
1138 const ErrorCallback
& error_callback
,
1139 const base::File::Info
& file_info
) {
1140 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1142 if (file_info
.is_directory
) {
1143 error_callback
.Run(base::File::FILE_ERROR_NOT_A_FILE
);
1146 if (CachedPathToId(file_path
, &file_id
))
1147 RunDeleteObjectOnUIThread(file_path
, file_id
, success_callback
,
1150 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
1154 void MTPDeviceDelegateImplLinux::DeleteDirectoryInternal(
1155 const base::FilePath
& file_path
,
1156 const DeleteDirectorySuccessCallback
& success_callback
,
1157 const ErrorCallback
& error_callback
,
1158 const base::File::Info
& file_info
) {
1159 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1161 if (!file_info
.is_directory
) {
1162 error_callback
.Run(base::File::FILE_ERROR_NOT_A_DIRECTORY
);
1166 uint32 directory_id
;
1167 if (!CachedPathToId(file_path
, &directory_id
)) {
1168 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
1172 // Checks the cache first. If it has children in cache, the directory cannot
1174 FileIdToMTPFileNodeMap::const_iterator it
=
1175 file_id_to_node_map_
.find(directory_id
);
1176 if (it
!= file_id_to_node_map_
.end() && it
->second
->HasChildren()) {
1177 error_callback
.Run(base::File::FILE_ERROR_NOT_EMPTY
);
1181 // Since the directory can contain a file even if the cache returns it as
1182 // empty, read the directory and confirm the directory is actually empty.
1183 const MTPDeviceTaskHelper::ReadDirectorySuccessCallback
1184 success_callback_wrapper
= base::Bind(
1185 &MTPDeviceDelegateImplLinux::OnDidReadDirectoryToDeleteDirectory
,
1186 weak_ptr_factory_
.GetWeakPtr(), file_path
, directory_id
,
1187 success_callback
, error_callback
);
1188 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper
=
1189 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
1190 weak_ptr_factory_
.GetWeakPtr(), error_callback
, directory_id
);
1191 const base::Closure closure
= base::Bind(
1192 &ReadDirectoryOnUIThread
, storage_name_
, read_only_
, directory_id
,
1193 1 /* max_size */, success_callback_wrapper
, error_callback_wrapper
);
1194 EnsureInitAndRunTask(PendingTaskInfo(
1195 base::FilePath(), content::BrowserThread::UI
, FROM_HERE
, closure
));
1198 void MTPDeviceDelegateImplLinux::CreateSingleDirectory(
1199 const base::FilePath
& directory_path
,
1200 const bool exclusive
,
1201 const CreateDirectorySuccessCallback
& success_callback
,
1202 const ErrorCallback
& error_callback
) {
1203 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1205 const GetFileInfoSuccessCallback success_callback_wrapper
= base::Bind(
1206 &MTPDeviceDelegateImplLinux::OnPathAlreadyExistsForCreateSingleDirectory
,
1207 weak_ptr_factory_
.GetWeakPtr(), exclusive
, success_callback
,
1209 const ErrorCallback error_callback_wrapper
= base::Bind(
1210 &MTPDeviceDelegateImplLinux::OnPathDoesNotExistForCreateSingleDirectory
,
1211 weak_ptr_factory_
.GetWeakPtr(), directory_path
, success_callback
,
1213 const base::Closure closure
=
1214 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal
,
1215 weak_ptr_factory_
.GetWeakPtr(), directory_path
,
1216 success_callback_wrapper
, error_callback_wrapper
);
1217 EnsureInitAndRunTask(PendingTaskInfo(
1218 base::FilePath(), content::BrowserThread::IO
, FROM_HERE
, closure
));
1219 PendingRequestDone();
1222 void MTPDeviceDelegateImplLinux::OnDidReadDirectoryToCreateDirectory(
1223 const std::vector
<base::FilePath
>& components
,
1224 const bool exclusive
,
1225 const CreateDirectorySuccessCallback
& success_callback
,
1226 const ErrorCallback
& error_callback
,
1227 const storage::AsyncFileUtil::EntryList
& /* file_list */,
1228 const bool has_more
) {
1229 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1232 return; // Wait until all entries have been read.
1234 const base::Closure closure
=
1235 base::Bind(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal
,
1236 weak_ptr_factory_
.GetWeakPtr(), components
, exclusive
,
1237 success_callback
, error_callback
);
1238 EnsureInitAndRunTask(PendingTaskInfo(
1239 base::FilePath(), content::BrowserThread::IO
, FROM_HERE
, closure
));
1242 void MTPDeviceDelegateImplLinux::OnDidReadDirectoryToDeleteDirectory(
1243 const base::FilePath
& directory_path
,
1244 const uint32 directory_id
,
1245 const DeleteDirectorySuccessCallback
& success_callback
,
1246 const ErrorCallback
& error_callback
,
1247 const storage::AsyncFileUtil::EntryList
& entries
,
1248 const bool has_more
) {
1249 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1252 if (entries
.size() > 0) {
1253 error_callback
.Run(base::File::FILE_ERROR_NOT_EMPTY
);
1255 RunDeleteObjectOnUIThread(directory_path
, directory_id
, success_callback
,
1259 PendingRequestDone();
1262 void MTPDeviceDelegateImplLinux::RunDeleteObjectOnUIThread(
1263 const base::FilePath
& object_path
,
1264 const uint32 object_id
,
1265 const DeleteObjectSuccessCallback
& success_callback
,
1266 const ErrorCallback
& error_callback
) {
1267 const MTPDeviceTaskHelper::DeleteObjectSuccessCallback
1268 success_callback_wrapper
=
1269 base::Bind(&MTPDeviceDelegateImplLinux::OnDidDeleteObject
,
1270 weak_ptr_factory_
.GetWeakPtr(), object_path
, object_id
,
1273 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper
=
1274 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeleteFileOrDirectoryError
,
1275 weak_ptr_factory_
.GetWeakPtr(), error_callback
);
1277 const base::Closure closure
=
1278 base::Bind(&DeleteObjectOnUIThread
, storage_name_
, read_only_
, object_id
,
1279 success_callback_wrapper
, error_callback_wrapper
);
1280 EnsureInitAndRunTask(PendingTaskInfo(
1281 base::FilePath(), content::BrowserThread::UI
, FROM_HERE
, closure
));
1284 void MTPDeviceDelegateImplLinux::EnsureInitAndRunTask(
1285 const PendingTaskInfo
& task_info
) {
1286 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1287 if ((init_state_
== INITIALIZED
) && !task_in_progress_
) {
1292 // Only *Internal functions have empty paths. Since they are the continuation
1293 // of the current running task, they get to cut in line.
1294 if (task_info
.path
.empty())
1295 pending_tasks_
.push_front(task_info
);
1297 pending_tasks_
.push_back(task_info
);
1299 if (init_state_
== UNINITIALIZED
) {
1300 init_state_
= PENDING_INIT
;
1301 task_in_progress_
= true;
1302 content::BrowserThread::PostTask(
1303 content::BrowserThread::UI
, FROM_HERE
,
1304 base::Bind(&OpenStorageOnUIThread
, storage_name_
, read_only_
,
1305 base::Bind(&MTPDeviceDelegateImplLinux::OnInitCompleted
,
1306 weak_ptr_factory_
.GetWeakPtr())));
1310 void MTPDeviceDelegateImplLinux::RunTask(const PendingTaskInfo
& task_info
) {
1311 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1312 DCHECK_EQ(INITIALIZED
, init_state_
);
1313 DCHECK(!task_in_progress_
);
1314 task_in_progress_
= true;
1316 bool need_to_check_cache
= !task_info
.path
.empty();
1317 if (need_to_check_cache
) {
1318 base::FilePath uncached_path
=
1319 NextUncachedPathComponent(task_info
.path
, task_info
.cached_path
);
1320 if (!uncached_path
.empty()) {
1321 // Save the current task and do a cache lookup first.
1322 pending_tasks_
.push_front(task_info
);
1323 FillFileCache(uncached_path
);
1328 content::BrowserThread::PostTask(task_info
.thread_id
,
1333 void MTPDeviceDelegateImplLinux::WriteDataIntoSnapshotFile(
1334 const base::File::Info
& file_info
) {
1335 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1336 DCHECK(current_snapshot_request_info_
.get());
1337 DCHECK_GT(file_info
.size
, 0);
1338 DCHECK(task_in_progress_
);
1339 SnapshotRequestInfo
request_info(
1340 current_snapshot_request_info_
->file_id
,
1341 current_snapshot_request_info_
->snapshot_file_path
,
1343 &MTPDeviceDelegateImplLinux::OnDidWriteDataIntoSnapshotFile
,
1344 weak_ptr_factory_
.GetWeakPtr()),
1346 &MTPDeviceDelegateImplLinux::OnWriteDataIntoSnapshotFileError
,
1347 weak_ptr_factory_
.GetWeakPtr()));
1349 base::Closure task_closure
= base::Bind(&WriteDataIntoSnapshotFileOnUIThread
,
1354 content::BrowserThread::PostTask(content::BrowserThread::UI
,
1359 void MTPDeviceDelegateImplLinux::PendingRequestDone() {
1360 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1361 DCHECK(task_in_progress_
);
1362 task_in_progress_
= false;
1363 ProcessNextPendingRequest();
1366 void MTPDeviceDelegateImplLinux::ProcessNextPendingRequest() {
1367 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1368 DCHECK(!task_in_progress_
);
1369 if (pending_tasks_
.empty())
1372 PendingTaskInfo task_info
= pending_tasks_
.front();
1373 pending_tasks_
.pop_front();
1377 void MTPDeviceDelegateImplLinux::OnInitCompleted(bool succeeded
) {
1378 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1379 init_state_
= succeeded
? INITIALIZED
: UNINITIALIZED
;
1380 PendingRequestDone();
1383 void MTPDeviceDelegateImplLinux::OnDidGetFileInfo(
1384 const GetFileInfoSuccessCallback
& success_callback
,
1385 const base::File::Info
& file_info
) {
1386 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1387 success_callback
.Run(file_info
);
1388 PendingRequestDone();
1391 void MTPDeviceDelegateImplLinux::OnPathAlreadyExistsForCreateSingleDirectory(
1392 const bool exclusive
,
1393 const CreateDirectorySuccessCallback
& success_callback
,
1394 const ErrorCallback
& error_callback
,
1395 const base::File::Info
& file_info
) {
1396 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1398 if (!file_info
.is_directory
|| exclusive
)
1399 error_callback
.Run(base::File::FILE_ERROR_EXISTS
);
1401 success_callback
.Run();
1404 void MTPDeviceDelegateImplLinux::OnPathDoesNotExistForCreateSingleDirectory(
1405 const base::FilePath
& directory_path
,
1406 const CreateDirectorySuccessCallback
& success_callback
,
1407 const ErrorCallback
& error_callback
,
1408 const base::File::Error error
) {
1409 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1411 if (error
!= base::File::FILE_ERROR_NOT_FOUND
) {
1412 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
1417 if (!CachedPathToId(directory_path
.DirName(), &parent_id
)) {
1418 error_callback
.Run(base::File::FILE_ERROR_NOT_FOUND
);
1422 const MTPDeviceTaskHelper::CreateDirectorySuccessCallback
1423 success_callback_wrapper
= base::Bind(
1424 &MTPDeviceDelegateImplLinux::OnDidCreateSingleDirectory
,
1425 weak_ptr_factory_
.GetWeakPtr(), directory_path
, success_callback
);
1426 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper
=
1427 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
1428 weak_ptr_factory_
.GetWeakPtr(), error_callback
, parent_id
);
1429 const base::Closure closure
=
1430 base::Bind(&CreateDirectoryOnUIThread
, storage_name_
, read_only_
,
1431 parent_id
, directory_path
.BaseName().value(),
1432 success_callback_wrapper
, error_callback_wrapper
);
1433 EnsureInitAndRunTask(PendingTaskInfo(
1434 base::FilePath(), content::BrowserThread::UI
, FROM_HERE
, closure
));
1437 void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory(
1439 const ReadDirectorySuccessCallback
& success_callback
,
1440 const ErrorCallback
& error_callback
,
1441 const base::File::Info
& file_info
) {
1442 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1443 DCHECK(task_in_progress_
);
1444 if (!file_info
.is_directory
) {
1445 return HandleDeviceFileError(error_callback
,
1447 base::File::FILE_ERROR_NOT_A_DIRECTORY
);
1450 base::Closure task_closure
= base::Bind(
1451 &ReadDirectoryOnUIThread
, storage_name_
, read_only_
, dir_id
,
1453 base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadDirectory
,
1454 weak_ptr_factory_
.GetWeakPtr(), dir_id
, success_callback
),
1455 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError
,
1456 weak_ptr_factory_
.GetWeakPtr(), error_callback
, dir_id
));
1457 content::BrowserThread::PostTask(content::BrowserThread::UI
,
1462 void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToCreateSnapshotFile(
1463 scoped_ptr
<SnapshotRequestInfo
> snapshot_request_info
,
1464 const base::File::Info
& file_info
) {
1465 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1466 DCHECK(!current_snapshot_request_info_
.get());
1467 DCHECK(snapshot_request_info
.get());
1468 DCHECK(task_in_progress_
);
1469 base::File::Error error
= base::File::FILE_OK
;
1470 if (file_info
.is_directory
)
1471 error
= base::File::FILE_ERROR_NOT_A_FILE
;
1472 else if (file_info
.size
< 0 || file_info
.size
> kuint32max
)
1473 error
= base::File::FILE_ERROR_FAILED
;
1475 if (error
!= base::File::FILE_OK
)
1476 return HandleDeviceFileError(snapshot_request_info
->error_callback
,
1477 snapshot_request_info
->file_id
,
1480 base::File::Info
snapshot_file_info(file_info
);
1481 // Modify the last modified time to null. This prevents the time stamp
1482 // verfication in LocalFileStreamReader.
1483 snapshot_file_info
.last_modified
= base::Time();
1485 current_snapshot_request_info_
.reset(snapshot_request_info
.release());
1486 if (file_info
.size
== 0) {
1487 // Empty snapshot file.
1488 return OnDidWriteDataIntoSnapshotFile(
1489 snapshot_file_info
, current_snapshot_request_info_
->snapshot_file_path
);
1491 WriteDataIntoSnapshotFile(snapshot_file_info
);
1494 void MTPDeviceDelegateImplLinux::OnDidGetDestFileInfoToCopyFileFromLocal(
1495 const ErrorCallback
& error_callback
,
1496 const base::File::Info
& file_info
) {
1497 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1499 if (file_info
.is_directory
)
1500 error_callback
.Run(base::File::FILE_ERROR_INVALID_OPERATION
);
1502 error_callback
.Run(base::File::FILE_ERROR_FAILED
);
1505 void MTPDeviceDelegateImplLinux::OnGetDestFileInfoErrorToCopyFileFromLocal(
1506 const base::FilePath
& source_file_path
,
1507 const base::FilePath
& device_file_path
,
1508 const CopyFileFromLocalSuccessCallback
& success_callback
,
1509 const ErrorCallback
& error_callback
,
1510 const base::File::Error error
) {
1511 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1513 if (error
!= base::File::FILE_ERROR_NOT_FOUND
) {
1514 error_callback
.Run(error
);
1518 content::BrowserThread::PostTaskAndReplyWithResult(
1519 content::BrowserThread::FILE, FROM_HERE
,
1520 base::Bind(&OpenFileDescriptor
, source_file_path
.value().c_str(),
1522 base::Bind(&MTPDeviceDelegateImplLinux::OnDidOpenFDToCopyFileFromLocal
,
1523 weak_ptr_factory_
.GetWeakPtr(), device_file_path
,
1524 success_callback
, error_callback
));
1527 void MTPDeviceDelegateImplLinux::OnDidCreateSingleDirectory(
1528 const base::FilePath
& directory_path
,
1529 const CreateDirectorySuccessCallback
& success_callback
) {
1530 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1532 success_callback
.Run();
1533 NotifyFileChange(directory_path
.DirName(),
1534 storage::WatcherManager::ChangeType::CHANGED
);
1535 PendingRequestDone();
1538 void MTPDeviceDelegateImplLinux::OnDidCreateParentDirectoryToCreateDirectory(
1539 const base::FilePath
& created_directory
,
1540 const std::vector
<base::FilePath
>& components
,
1541 const bool exclusive
,
1542 const CreateDirectorySuccessCallback
& success_callback
,
1543 const ErrorCallback
& error_callback
) {
1544 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1546 // Calls ReadDirectoryInternal to fill the cache for created directory.
1547 // Calls ReadDirectoryInternal in this method to call it via
1548 // EnsureInitAndRunTask.
1549 const ReadDirectorySuccessCallback
& success_callback_wrapper
= base::Bind(
1550 &MTPDeviceDelegateImplLinux::OnDidReadDirectoryToCreateDirectory
,
1551 weak_ptr_factory_
.GetWeakPtr(), components
, exclusive
, success_callback
,
1553 const base::Closure closure
=
1554 base::Bind(&MTPDeviceDelegateImplLinux::ReadDirectoryInternal
,
1555 weak_ptr_factory_
.GetWeakPtr(), created_directory
.DirName(),
1556 success_callback_wrapper
, error_callback
);
1557 EnsureInitAndRunTask(PendingTaskInfo(
1558 base::FilePath(), content::BrowserThread::IO
, FROM_HERE
, closure
));
1561 void MTPDeviceDelegateImplLinux::OnCreateParentDirectoryErrorToCreateDirectory(
1562 const ErrorCallback
& callback
,
1563 const base::File::Error error
) {
1564 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1566 callback
.Run(base::File::FILE_ERROR_FAILED
);
1569 void MTPDeviceDelegateImplLinux::OnDidReadDirectory(
1571 const ReadDirectorySuccessCallback
& success_callback
,
1572 const storage::AsyncFileUtil::EntryList
& file_list
,
1574 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1576 FileIdToMTPFileNodeMap::iterator it
= file_id_to_node_map_
.find(dir_id
);
1577 DCHECK(it
!= file_id_to_node_map_
.end());
1578 MTPFileNode
* dir_node
= it
->second
;
1580 // Traverse the MTPFileNode tree to reconstuct the full path for |dir_id|.
1581 std::deque
<std::string
> dir_path_parts
;
1582 MTPFileNode
* parent_node
= dir_node
;
1583 while (parent_node
->parent()) {
1584 dir_path_parts
.push_front(parent_node
->file_name());
1585 parent_node
= parent_node
->parent();
1587 base::FilePath dir_path
= device_path_
;
1588 for (size_t i
= 0; i
< dir_path_parts
.size(); ++i
)
1589 dir_path
= dir_path
.Append(dir_path_parts
[i
]);
1591 storage::AsyncFileUtil::EntryList normalized_file_list
;
1592 for (size_t i
= 0; i
< file_list
.size(); ++i
) {
1593 normalized_file_list
.push_back(file_list
[i
]);
1594 storage::DirectoryEntry
& entry
= normalized_file_list
.back();
1596 // |entry.name| has the file id encoded in it. Decode here.
1597 size_t separator_idx
= entry
.name
.find_last_of(',');
1598 DCHECK_NE(std::string::npos
, separator_idx
);
1599 std::string file_id_str
= entry
.name
.substr(separator_idx
);
1600 file_id_str
= file_id_str
.substr(1); // Get rid of the comma.
1602 bool ret
= base::StringToUint(file_id_str
, &file_id
);
1604 entry
.name
= entry
.name
.substr(0, separator_idx
);
1606 // Refresh the in memory tree.
1607 dir_node
->EnsureChildExists(entry
.name
, file_id
);
1608 child_nodes_seen_
.insert(entry
.name
);
1610 // Add to |file_info_cache_|.
1611 file_info_cache_
[dir_path
.Append(entry
.name
)] = entry
;
1614 success_callback
.Run(normalized_file_list
, has_more
);
1616 return; // Wait to be called again.
1618 // Last call, finish book keeping and continue with the next request.
1619 dir_node
->ClearNonexistentChildren(child_nodes_seen_
);
1620 child_nodes_seen_
.clear();
1621 file_info_cache_
.clear();
1623 PendingRequestDone();
1626 void MTPDeviceDelegateImplLinux::OnDidWriteDataIntoSnapshotFile(
1627 const base::File::Info
& file_info
,
1628 const base::FilePath
& snapshot_file_path
) {
1629 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1630 DCHECK(current_snapshot_request_info_
.get());
1631 current_snapshot_request_info_
->success_callback
.Run(
1632 file_info
, snapshot_file_path
);
1633 current_snapshot_request_info_
.reset();
1634 PendingRequestDone();
1637 void MTPDeviceDelegateImplLinux::OnWriteDataIntoSnapshotFileError(
1638 base::File::Error error
) {
1639 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1640 DCHECK(current_snapshot_request_info_
.get());
1641 current_snapshot_request_info_
->error_callback
.Run(error
);
1642 current_snapshot_request_info_
.reset();
1643 PendingRequestDone();
1646 void MTPDeviceDelegateImplLinux::OnDidReadBytes(
1647 const ReadBytesSuccessCallback
& success_callback
,
1648 const base::File::Info
& file_info
, int bytes_read
) {
1649 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1650 success_callback
.Run(file_info
, bytes_read
);
1651 PendingRequestDone();
1654 void MTPDeviceDelegateImplLinux::OnDidFillFileCache(
1655 const base::FilePath
& path
,
1656 const storage::AsyncFileUtil::EntryList
& /* file_list */,
1658 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1659 DCHECK(path
.IsParent(pending_tasks_
.front().path
));
1661 return; // Wait until all entries have been read.
1662 pending_tasks_
.front().cached_path
= path
;
1665 void MTPDeviceDelegateImplLinux::OnFillFileCacheFailed(
1666 base::File::Error
/* error */) {
1667 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1668 // When filling the cache fails for the task at the front of the queue, clear
1669 // the path of the task so it will not try to do any more caching. Instead,
1670 // the task will just run and fail the CachedPathToId() lookup.
1671 pending_tasks_
.front().path
.clear();
1674 void MTPDeviceDelegateImplLinux::OnDidCreateTemporaryFileToCopyFileLocal(
1675 const base::FilePath
& source_file_path
,
1676 const base::FilePath
& device_file_path
,
1677 const CopyFileProgressCallback
& progress_callback
,
1678 const CopyFileLocalSuccessCallback
& success_callback
,
1679 const ErrorCallback
& error_callback
,
1680 const base::FilePath
& temporary_file_path
) {
1681 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1683 if (temporary_file_path
.empty()) {
1684 error_callback
.Run(base::File::FILE_ERROR_FAILED
);
1689 source_file_path
, temporary_file_path
,
1691 &MTPDeviceDelegateImplLinux::OnDidCreateSnapshotFileOfCopyFileLocal
,
1692 weak_ptr_factory_
.GetWeakPtr(), device_file_path
, progress_callback
,
1693 success_callback
, error_callback
),
1694 base::Bind(&MTPDeviceDelegateImplLinux::HandleCopyFileLocalError
,
1695 weak_ptr_factory_
.GetWeakPtr(), error_callback
,
1696 temporary_file_path
));
1699 void MTPDeviceDelegateImplLinux::OnDidCreateSnapshotFileOfCopyFileLocal(
1700 const base::FilePath
& device_file_path
,
1701 const CopyFileProgressCallback
& progress_callback
,
1702 const CopyFileLocalSuccessCallback
& success_callback
,
1703 const ErrorCallback
& error_callback
,
1704 const base::File::Info
& file_info
,
1705 const base::FilePath
& temporary_file_path
) {
1706 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1708 // Consider that half of copy is completed by creating a temporary file.
1709 progress_callback
.Run(file_info
.size
/ 2);
1711 // TODO(yawano): Avoid to call external method from internal code.
1713 temporary_file_path
, device_file_path
,
1715 &MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocalOfCopyFileLocal
,
1716 weak_ptr_factory_
.GetWeakPtr(), success_callback
,
1717 temporary_file_path
),
1718 base::Bind(&MTPDeviceDelegateImplLinux::HandleCopyFileLocalError
,
1719 weak_ptr_factory_
.GetWeakPtr(), error_callback
,
1720 temporary_file_path
));
1723 void MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocalOfCopyFileLocal(
1724 const CopyFileFromLocalSuccessCallback success_callback
,
1725 const base::FilePath
& temporary_file_path
) {
1726 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1728 DeleteTemporaryFile(temporary_file_path
);
1729 success_callback
.Run();
1732 void MTPDeviceDelegateImplLinux::OnDidMoveFileLocalWithRename(
1733 const MoveFileLocalSuccessCallback
& success_callback
,
1734 const base::FilePath
& source_file_path
,
1735 const uint32 file_id
) {
1736 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1738 EvictCachedPathToId(file_id
);
1739 success_callback
.Run();
1740 NotifyFileChange(source_file_path
,
1741 storage::WatcherManager::ChangeType::DELETED
);
1742 NotifyFileChange(source_file_path
.DirName(),
1743 storage::WatcherManager::ChangeType::CHANGED
);
1744 PendingRequestDone();
1747 void MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocal(
1748 const CopyFileFromLocalSuccessCallback
& success_callback
,
1749 const base::FilePath
& file_path
,
1750 const int source_file_descriptor
) {
1751 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1753 const base::Closure closure
= base::Bind(&CloseFileDescriptor
,
1754 source_file_descriptor
);
1756 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE
,
1759 success_callback
.Run();
1760 NotifyFileChange(file_path
.DirName(),
1761 storage::WatcherManager::ChangeType::CHANGED
);
1762 PendingRequestDone();
1765 void MTPDeviceDelegateImplLinux::HandleCopyFileLocalError(
1766 const ErrorCallback
& error_callback
,
1767 const base::FilePath
& temporary_file_path
,
1768 const base::File::Error error
) {
1769 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1771 DeleteTemporaryFile(temporary_file_path
);
1772 error_callback
.Run(error
);
1775 void MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError(
1776 const ErrorCallback
& error_callback
,
1777 const int source_file_descriptor
,
1778 base::File::Error error
) {
1779 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1781 const base::Closure closure
= base::Bind(&CloseFileDescriptor
,
1782 source_file_descriptor
);
1784 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE
,
1787 error_callback
.Run(error
);
1788 PendingRequestDone();
1791 void MTPDeviceDelegateImplLinux::OnDidDeleteObject(
1792 const base::FilePath
& object_path
,
1793 const uint32 object_id
,
1794 const DeleteObjectSuccessCallback success_callback
) {
1795 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1797 EvictCachedPathToId(object_id
);
1798 success_callback
.Run();
1799 NotifyFileChange(object_path
, storage::WatcherManager::ChangeType::DELETED
);
1800 NotifyFileChange(object_path
.DirName(),
1801 storage::WatcherManager::ChangeType::CHANGED
);
1802 PendingRequestDone();
1805 void MTPDeviceDelegateImplLinux::HandleDeleteFileOrDirectoryError(
1806 const ErrorCallback
& error_callback
,
1807 base::File::Error error
) {
1808 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1810 error_callback
.Run(error
);
1811 PendingRequestDone();
1814 void MTPDeviceDelegateImplLinux::HandleDeviceFileError(
1815 const ErrorCallback
& error_callback
,
1817 base::File::Error error
) {
1818 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1820 EvictCachedPathToId(file_id
);
1821 error_callback
.Run(error
);
1822 PendingRequestDone();
1825 base::FilePath
MTPDeviceDelegateImplLinux::NextUncachedPathComponent(
1826 const base::FilePath
& path
,
1827 const base::FilePath
& cached_path
) const {
1828 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1829 DCHECK(cached_path
.empty() || cached_path
.IsParent(path
));
1831 base::FilePath uncached_path
;
1832 std::string device_relpath
= GetDeviceRelativePath(device_path_
, path
);
1833 if (!device_relpath
.empty() && device_relpath
!= kRootPath
) {
1834 uncached_path
= device_path_
;
1835 std::vector
<std::string
> device_relpath_components
= base::SplitString(
1836 device_relpath
, "/", base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
);
1837 DCHECK(!device_relpath_components
.empty());
1838 bool all_components_cached
= true;
1839 const MTPFileNode
* current_node
= root_node_
.get();
1840 for (size_t i
= 0; i
< device_relpath_components
.size(); ++i
) {
1841 current_node
= current_node
->GetChild(device_relpath_components
[i
]);
1842 if (!current_node
) {
1843 // With a cache miss, check if it is a genuine failure. If so, pretend
1844 // the entire |path| is cached, so there is no further attempt to do
1845 // more caching. The actual operation will then fail.
1846 all_components_cached
=
1847 !cached_path
.empty() && (uncached_path
== cached_path
);
1850 uncached_path
= uncached_path
.Append(device_relpath_components
[i
]);
1852 if (all_components_cached
)
1853 uncached_path
.clear();
1855 return uncached_path
;
1858 void MTPDeviceDelegateImplLinux::FillFileCache(
1859 const base::FilePath
& uncached_path
) {
1860 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1861 DCHECK(task_in_progress_
);
1863 ReadDirectorySuccessCallback success_callback
=
1864 base::Bind(&MTPDeviceDelegateImplLinux::OnDidFillFileCache
,
1865 weak_ptr_factory_
.GetWeakPtr(),
1867 ErrorCallback error_callback
=
1868 base::Bind(&MTPDeviceDelegateImplLinux::OnFillFileCacheFailed
,
1869 weak_ptr_factory_
.GetWeakPtr());
1870 ReadDirectoryInternal(uncached_path
, success_callback
, error_callback
);
1874 bool MTPDeviceDelegateImplLinux::CachedPathToId(const base::FilePath
& path
,
1878 std::string device_relpath
= GetDeviceRelativePath(device_path_
, path
);
1879 if (device_relpath
.empty())
1881 std::vector
<std::string
> device_relpath_components
;
1882 if (device_relpath
!= kRootPath
) {
1883 device_relpath_components
= base::SplitString(
1884 device_relpath
, "/", base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
);
1886 const MTPFileNode
* current_node
= root_node_
.get();
1887 for (size_t i
= 0; i
< device_relpath_components
.size(); ++i
) {
1888 current_node
= current_node
->GetChild(device_relpath_components
[i
]);
1892 *id
= current_node
->file_id();
1896 void MTPDeviceDelegateImplLinux::EvictCachedPathToId(const uint32 id
) {
1897 FileIdToMTPFileNodeMap::iterator it
= file_id_to_node_map_
.find(id
);
1898 if (it
!= file_id_to_node_map_
.end()) {
1899 DCHECK(!it
->second
->HasChildren());
1900 MTPFileNode
* parent
= it
->second
->parent();
1902 const bool ret
= parent
->DeleteChild(id
);
1908 void CreateMTPDeviceAsyncDelegate(
1909 const std::string
& device_location
,
1910 const bool read_only
,
1911 const CreateMTPDeviceAsyncDelegateCallback
& callback
) {
1912 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1913 callback
.Run(new MTPDeviceDelegateImplLinux(device_location
, read_only
));