Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / media_galleries / linux / mtp_device_delegate_impl_linux.cc
blobb6f8a346f532bc976b3fab2157fb97ffce7730c7
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h"
7 #include <fcntl.h>
8 #include <algorithm>
9 #include <vector>
11 #include "base/bind.h"
12 #include "base/files/file_util.h"
13 #include "base/numerics/safe_conversions.h"
14 #include "base/posix/eintr_wrapper.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_split.h"
17 #include "base/strings/string_util.h"
18 #include "chrome/browser/media_galleries/linux/mtp_device_task_helper.h"
19 #include "chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.h"
20 #include "chrome/browser/media_galleries/linux/snapshot_file_details.h"
21 #include "net/base/io_buffer.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
24 namespace {
26 // File path separator constant.
27 const char kRootPath[] = "/";
29 // Returns the device relative file path given |file_path|.
30 // E.g.: If the |file_path| is "/usb:2,2:12345/DCIM" and |registered_dev_path|
31 // is "/usb:2,2:12345", this function returns the device relative path which is
32 // "DCIM".
33 // In the special case when |registered_dev_path| and |file_path| are the same,
34 // return |kRootPath|.
35 std::string GetDeviceRelativePath(const base::FilePath& registered_dev_path,
36 const base::FilePath& file_path) {
37 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
38 DCHECK(!registered_dev_path.empty());
39 DCHECK(!file_path.empty());
40 std::string result;
41 if (registered_dev_path == file_path) {
42 result = kRootPath;
43 } else {
44 base::FilePath relative_path;
45 if (registered_dev_path.AppendRelativePath(file_path, &relative_path)) {
46 DCHECK(!relative_path.empty());
47 result = relative_path.value();
50 return result;
53 // Returns the MTPDeviceTaskHelper object associated with the MTP device
54 // storage.
56 // |storage_name| specifies the name of the storage device.
57 // |read_only| specifies the mode of the storage device.
58 // Returns NULL if the |storage_name| is no longer valid (e.g. because the
59 // corresponding storage device is detached, etc).
60 MTPDeviceTaskHelper* GetDeviceTaskHelperForStorage(
61 const std::string& storage_name,
62 const bool read_only) {
63 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
64 return MTPDeviceTaskHelperMapService::GetInstance()->GetDeviceTaskHelper(
65 storage_name,
66 read_only);
69 // Opens the storage device for communication.
71 // Called on the UI thread to dispatch the request to the
72 // MediaTransferProtocolManager.
74 // |storage_name| specifies the name of the storage device.
75 // |read_only| specifies the mode of the storage device.
76 // |reply_callback| is called when the OpenStorage request completes.
77 // |reply_callback| runs on the IO thread.
78 void OpenStorageOnUIThread(
79 const std::string& storage_name,
80 const bool read_only,
81 const MTPDeviceTaskHelper::OpenStorageCallback& reply_callback) {
82 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
83 MTPDeviceTaskHelper* task_helper =
84 GetDeviceTaskHelperForStorage(storage_name, read_only);
85 if (!task_helper) {
86 task_helper =
87 MTPDeviceTaskHelperMapService::GetInstance()->CreateDeviceTaskHelper(
88 storage_name, read_only);
90 task_helper->OpenStorage(storage_name, read_only, reply_callback);
93 // 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);
112 if (!task_helper)
113 return;
114 task_helper->CreateDirectory(parent_id, directory_name, success_callback,
115 error_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);
140 if (!task_helper)
141 return;
142 task_helper->ReadDirectory(directory_id, max_size, success_callback,
143 error_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,
159 uint32 file_id,
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);
165 if (!task_helper)
166 return;
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
180 // snapshot file.
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);
192 if (!task_helper)
193 return;
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);
212 if (!task_helper)
213 return;
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);
236 if (!task_helper)
237 return;
238 task_helper->RenameObject(object_id, new_name, success_callback,
239 error_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&
260 success_callback,
261 const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
262 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
263 MTPDeviceTaskHelper* task_helper =
264 GetDeviceTaskHelperForStorage(storage_name, read_only);
265 if (!task_helper)
266 return;
267 task_helper->CopyFileFromLocal(storage_name, source_file_descriptor,
268 parent_id, file_name, success_callback,
269 error_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);
292 if (!task_helper)
293 return;
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);
308 if (!task_helper)
309 return;
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,
323 const int flags) {
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);
331 if (errno == ENOENT)
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) {
354 } // namespace
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)
361 : path(path),
362 thread_id(thread_id),
363 location(location),
364 task(task) {
367 MTPDeviceDelegateImplLinux::PendingTaskInfo::~PendingTaskInfo() {
370 // Represents a file on the MTP device.
371 // Lives on the IO thread.
372 class MTPDeviceDelegateImplLinux::MTPFileNode {
373 public:
374 MTPFileNode(uint32 file_id,
375 const std::string& file_name,
376 MTPFileNode* parent,
377 FileIdToMTPFileNodeMap* file_id_to_node_map);
378 ~MTPFileNode();
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_; }
396 private:
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(
411 uint32 file_id,
412 const std::string& file_name,
413 MTPFileNode* parent,
414 FileIdToMTPFileNodeMap* file_id_to_node_map)
415 : file_id_(file_id),
416 file_name_(file_name),
417 parent_(parent),
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,
440 uint32 id) {
441 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
442 const MTPFileNode* child = GetChild(name);
443 if (child && child->file_id() == id)
444 return;
446 children_.set(
447 name,
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))
458 continue;
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());
473 children_.erase(it);
474 return true;
477 return false;
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);
519 return;
522 // Decomposes |directory_path| to components. CreateDirectoryInternal creates
523 // directories by reading |components| from back.
524 std::vector<base::FilePath> components;
525 if (recursive) {
526 for (base::FilePath path = directory_path; path != device_path_;
527 path = path.DirName()) {
528 components.push_back(path);
530 } else {
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
550 // cached.
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);
564 return;
566 base::Closure closure =
567 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
568 weak_ptr_factory_.GetWeakPtr(),
569 file_path,
570 success_callback,
571 error_callback);
572 EnsureInitAndRunTask(PendingTaskInfo(file_path,
573 content::BrowserThread::IO,
574 FROM_HERE,
575 closure));
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(),
587 root,
588 success_callback,
589 error_callback);
590 EnsureInitAndRunTask(PendingTaskInfo(root,
591 content::BrowserThread::IO,
592 FROM_HERE,
593 closure));
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(),
607 device_file_path,
608 local_path,
609 success_callback,
610 error_callback);
611 EnsureInitAndRunTask(PendingTaskInfo(device_file_path,
612 content::BrowserThread::IO,
613 FROM_HERE,
614 closure));
617 bool MTPDeviceDelegateImplLinux::IsStreaming() {
618 return true;
621 void MTPDeviceDelegateImplLinux::ReadBytes(
622 const base::FilePath& device_file_path,
623 const scoped_refptr<net::IOBuffer>& buf,
624 int64 offset,
625 int buf_len,
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(),
633 device_file_path,
634 buf,
635 offset,
636 buf_len,
637 success_callback,
638 error_callback);
639 EnsureInitAndRunTask(PendingTaskInfo(device_file_path,
640 content::BrowserThread::IO,
641 FROM_HERE,
642 closure));
645 bool MTPDeviceDelegateImplLinux::IsReadOnly() const {
646 return read_only_;
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,
663 base::Bind(
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,
727 error_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,
747 error_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,
762 FROM_HERE,
763 base::Bind(&CloseStorageAndDestroyTaskHelperOnUIThread,
764 storage_name_,
765 read_only_));
766 delete this;
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);
775 uint32 file_id;
776 if (CachedPathToId(file_path, &file_id)) {
777 GetFileInfoSuccessCallback success_callback_wrapper =
778 base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfo,
779 weak_ptr_factory_.GetWeakPtr(),
780 success_callback);
781 ErrorCallback error_callback_wrapper =
782 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
783 weak_ptr_factory_.GetWeakPtr(),
784 error_callback,
785 file_id);
788 base::Closure closure = base::Bind(&GetFileInfoOnUIThread,
789 storage_name_,
790 read_only_,
791 file_id,
792 success_callback_wrapper,
793 error_callback_wrapper);
794 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
795 content::BrowserThread::UI,
796 FROM_HERE,
797 closure));
798 } else {
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.
818 uint32 parent_id;
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));
826 } else {
827 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
829 } else {
830 // Ensures that parent directories are created for recursive case.
831 uint32 directory_id;
832 if (CachedPathToId(current_component, &directory_id)) {
833 // Parent directory |current_component| already exists, continue creating
834 // directories.
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));
841 } else {
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,
848 error_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);
874 uint32 dir_id;
875 if (CachedPathToId(root, &dir_id)) {
876 GetFileInfoSuccessCallback success_callback_wrapper =
877 base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory,
878 weak_ptr_factory_.GetWeakPtr(),
879 dir_id,
880 success_callback,
881 error_callback);
882 ErrorCallback error_callback_wrapper =
883 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
884 weak_ptr_factory_.GetWeakPtr(),
885 error_callback,
886 dir_id);
887 base::Closure closure = base::Bind(&GetFileInfoOnUIThread,
888 storage_name_,
889 read_only_,
890 dir_id,
891 success_callback_wrapper,
892 error_callback_wrapper);
893 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
894 content::BrowserThread::UI,
895 FROM_HERE,
896 closure));
897 } else {
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);
910 uint32 file_id;
911 if (CachedPathToId(device_file_path, &file_id)) {
912 scoped_ptr<SnapshotRequestInfo> request_info(
913 new SnapshotRequestInfo(file_id,
914 local_path,
915 success_callback,
916 error_callback));
917 GetFileInfoSuccessCallback success_callback_wrapper =
918 base::Bind(
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(),
925 error_callback,
926 file_id);
927 base::Closure closure = base::Bind(&GetFileInfoOnUIThread,
928 storage_name_,
929 read_only_,
930 file_id,
931 success_callback_wrapper,
932 error_callback_wrapper);
933 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
934 content::BrowserThread::UI,
935 FROM_HERE,
936 closure));
937 } else {
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);
950 uint32 file_id;
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(),
956 success_callback),
957 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
958 weak_ptr_factory_.GetWeakPtr(),
959 error_callback,
960 file_id));
962 base::Closure closure =
963 base::Bind(&ReadBytesOnUIThread, storage_name_, read_only_, request);
964 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
965 content::BrowserThread::UI,
966 FROM_HERE,
967 closure));
968 } else {
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);
985 return;
988 if (source_file_path.DirName() == device_file_path.DirName()) {
989 // If a file is moved in a same directory, rename the file.
990 uint32 file_id;
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));
1005 } else {
1006 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
1008 } else {
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);
1032 return;
1035 const int source_file_descriptor = open_fd_result.first;
1036 uint32 parent_id;
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,
1048 storage_name_,
1049 read_only_,
1050 source_file_descriptor,
1051 parent_id,
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));
1058 } else {
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);
1073 } else {
1074 uint32 file_id;
1075 if (CachedPathToId(file_path, &file_id))
1076 RunDeleteObjectOnUIThread(file_id, success_callback, error_callback);
1077 else
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);
1091 return;
1094 uint32 directory_id;
1095 if (!CachedPathToId(file_path, &directory_id)) {
1096 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
1097 return;
1100 // Checks the cache first. If it has children in cache, the directory cannot
1101 // be empty.
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);
1106 return;
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,
1115 error_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,
1136 error_callback);
1137 const ErrorCallback error_callback_wrapper = base::Bind(
1138 &MTPDeviceDelegateImplLinux::OnPathDoesNotExistForCreateSingleDirectory,
1139 weak_ptr_factory_.GetWeakPtr(), directory_path, success_callback,
1140 error_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);
1159 if (has_more)
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);
1177 DCHECK(!has_more);
1179 if (entries.size() > 0)
1180 error_callback.Run(base::File::FILE_ERROR_NOT_EMPTY);
1181 else
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_) {
1211 RunTask(task_info);
1212 return;
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);
1219 else
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);
1247 return;
1251 content::BrowserThread::PostTask(task_info.thread_id,
1252 task_info.location,
1253 task_info.task);
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,
1265 base::Bind(
1266 &MTPDeviceDelegateImplLinux::OnDidWriteDataIntoSnapshotFile,
1267 weak_ptr_factory_.GetWeakPtr()),
1268 base::Bind(
1269 &MTPDeviceDelegateImplLinux::OnWriteDataIntoSnapshotFileError,
1270 weak_ptr_factory_.GetWeakPtr()));
1272 base::Closure task_closure = base::Bind(&WriteDataIntoSnapshotFileOnUIThread,
1273 storage_name_,
1274 read_only_,
1275 request_info,
1276 file_info);
1277 content::BrowserThread::PostTask(content::BrowserThread::UI,
1278 FROM_HERE,
1279 task_closure);
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())
1293 return;
1295 PendingTaskInfo task_info = pending_tasks_.front();
1296 pending_tasks_.pop_front();
1297 RunTask(task_info);
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);
1323 else
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);
1336 return;
1339 uint32 parent_id;
1340 if (!CachedPathToId(directory_path.DirName(), &parent_id)) {
1341 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
1342 return;
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(
1361 uint32 dir_id,
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,
1369 dir_id,
1370 base::File::FILE_ERROR_NOT_A_DIRECTORY);
1373 base::Closure task_closure = base::Bind(
1374 &ReadDirectoryOnUIThread, storage_name_, read_only_, dir_id,
1375 0 /* max_size */,
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,
1381 FROM_HERE,
1382 task_closure);
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,
1401 error);
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);
1424 else
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);
1438 return;
1441 content::BrowserThread::PostTaskAndReplyWithResult(
1442 content::BrowserThread::FILE, FROM_HERE,
1443 base::Bind(&OpenFileDescriptor, source_file_path.value().c_str(),
1444 O_RDONLY),
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,
1472 error_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(
1490 uint32 dir_id,
1491 const ReadDirectorySuccessCallback& success_callback,
1492 const storage::AsyncFileUtil::EntryList& file_list,
1493 bool has_more) {
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.
1521 uint32 file_id = 0;
1522 bool ret = base::StringToUint(file_id_str, &file_id);
1523 DCHECK(ret);
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);
1535 if (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 */,
1577 bool has_more) {
1578 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1579 DCHECK(path.IsParent(pending_tasks_.front().path));
1580 if (has_more)
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);
1605 return;
1608 CreateSnapshotFile(
1609 source_file_path, temporary_file_path,
1610 base::Bind(
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.
1632 CopyFileFromLocal(
1633 temporary_file_path, device_file_path,
1634 base::Bind(
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,
1671 closure);
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,
1697 closure);
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,
1724 uint32 file_id,
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);
1756 break;
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(),
1774 uncached_path);
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,
1783 uint32* id) const {
1784 DCHECK(id);
1786 std::string device_relpath = GetDeviceRelativePath(device_path_, path);
1787 if (device_relpath.empty())
1788 return false;
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]);
1795 if (!current_node)
1796 return false;
1798 *id = current_node->file_id();
1799 return true;
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();
1807 if (parent) {
1808 const bool ret = parent->DeleteChild(id);
1809 DCHECK(ret);
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));