Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Side by Side Diff: chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc

Issue 2358493002: Remove MTP support on Linux. (Closed)
Patch Set: move files Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <stddef.h>
10
11 #include <algorithm>
12 #include <limits>
13 #include <vector>
14
15 #include "base/bind.h"
16 #include "base/files/file_util.h"
17 #include "base/macros.h"
18 #include "base/memory/ptr_util.h"
19 #include "base/numerics/safe_conversions.h"
20 #include "base/posix/eintr_wrapper.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/string_split.h"
23 #include "base/strings/string_util.h"
24 #include "chrome/browser/media_galleries/linux/mtp_device_task_helper_map_servic e.h"
25 #include "chrome/browser/media_galleries/linux/snapshot_file_details.h"
26 #include "net/base/io_buffer.h"
27 #include "third_party/cros_system_api/dbus/service_constants.h"
28
29 namespace {
30
31 // File path separator constant.
32 const char kRootPath[] = "/";
33
34 // Returns the device relative file path given |file_path|.
35 // E.g.: If the |file_path| is "/usb:2,2:12345/DCIM" and |registered_dev_path|
36 // is "/usb:2,2:12345", this function returns the device relative path which is
37 // "DCIM".
38 // In the special case when |registered_dev_path| and |file_path| are the same,
39 // return |kRootPath|.
40 std::string GetDeviceRelativePath(const base::FilePath& registered_dev_path,
41 const base::FilePath& file_path) {
42 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
43 DCHECK(!registered_dev_path.empty());
44 DCHECK(!file_path.empty());
45 std::string result;
46 if (registered_dev_path == file_path) {
47 result = kRootPath;
48 } else {
49 base::FilePath relative_path;
50 if (registered_dev_path.AppendRelativePath(file_path, &relative_path)) {
51 DCHECK(!relative_path.empty());
52 result = relative_path.value();
53 }
54 }
55 return result;
56 }
57
58 // Returns the MTPDeviceTaskHelper object associated with the MTP device
59 // storage.
60 //
61 // |storage_name| specifies the name of the storage device.
62 // |read_only| specifies the mode of the storage device.
63 // Returns NULL if the |storage_name| is no longer valid (e.g. because the
64 // corresponding storage device is detached, etc).
65 MTPDeviceTaskHelper* GetDeviceTaskHelperForStorage(
66 const std::string& storage_name,
67 const bool read_only) {
68 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
69 return MTPDeviceTaskHelperMapService::GetInstance()->GetDeviceTaskHelper(
70 storage_name,
71 read_only);
72 }
73
74 // Opens the storage device for communication.
75 //
76 // Called on the UI thread to dispatch the request to the
77 // MediaTransferProtocolManager.
78 //
79 // |storage_name| specifies the name of the storage device.
80 // |read_only| specifies the mode of the storage device.
81 // |reply_callback| is called when the OpenStorage request completes.
82 // |reply_callback| runs on the IO thread.
83 void OpenStorageOnUIThread(
84 const std::string& storage_name,
85 const bool read_only,
86 const MTPDeviceTaskHelper::OpenStorageCallback& reply_callback) {
87 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
88 MTPDeviceTaskHelper* task_helper =
89 GetDeviceTaskHelperForStorage(storage_name, read_only);
90 if (!task_helper) {
91 task_helper =
92 MTPDeviceTaskHelperMapService::GetInstance()->CreateDeviceTaskHelper(
93 storage_name, read_only);
94 }
95 task_helper->OpenStorage(storage_name, read_only, reply_callback);
96 }
97
98 // Creates |directory_name| on |parent_id|.
99 //
100 // |storage_name| specifies the name of the storage device.
101 // |read_only| specifies the mode of the storage device.
102 // |parent_id| is an object id of the parent directory.
103 // |directory_name| is name of the new directory.
104 // |success_callback| is called when the directory is created successfully.
105 // |error_callback| is called when it fails to create a directory.
106 // |success_callback| and |error_callback| runs on the IO thread.
107 void CreateDirectoryOnUIThread(
108 const std::string& storage_name,
109 const bool read_only,
110 const uint32_t parent_id,
111 const std::string& directory_name,
112 const MTPDeviceTaskHelper::CreateDirectorySuccessCallback& success_callback,
113 const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
114 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
115 MTPDeviceTaskHelper* task_helper =
116 GetDeviceTaskHelperForStorage(storage_name, read_only);
117 if (!task_helper)
118 return;
119 task_helper->CreateDirectory(parent_id, directory_name, success_callback,
120 error_callback);
121 }
122
123 // Enumerates the |dir_id| directory file entries.
124 //
125 // Called on the UI thread to dispatch the request to the
126 // MediaTransferProtocolManager.
127 //
128 // |storage_name| specifies the name of the storage device.
129 // |read_only| specifies the mode of the storage device.
130 // |directory_id| is an id of a directory to read.
131 // |max_size| is a maximum size to read. Set 0 not to specify the maximum size.
132 // |success_callback| is called when the ReadDirectory request succeeds.
133 // |error_callback| is called when the ReadDirectory request fails.
134 // |success_callback| and |error_callback| runs on the IO thread.
135 void ReadDirectoryOnUIThread(
136 const std::string& storage_name,
137 const bool read_only,
138 const uint32_t directory_id,
139 const size_t max_size,
140 const MTPDeviceTaskHelper::ReadDirectorySuccessCallback& success_callback,
141 const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
142 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
143 MTPDeviceTaskHelper* task_helper =
144 GetDeviceTaskHelperForStorage(storage_name, read_only);
145 if (!task_helper)
146 return;
147 task_helper->ReadDirectory(directory_id, max_size, success_callback,
148 error_callback);
149 }
150
151 // Gets the |file_path| details.
152 //
153 // Called on the UI thread to dispatch the request to the
154 // MediaTransferProtocolManager.
155 //
156 // |storage_name| specifies the name of the storage device.
157 // |read_only| specifies the mode of the storage device.
158 // |success_callback| is called when the GetFileInfo request succeeds.
159 // |error_callback| is called when the GetFileInfo request fails.
160 // |success_callback| and |error_callback| runs on the IO thread.
161 void GetFileInfoOnUIThread(
162 const std::string& storage_name,
163 const bool read_only,
164 uint32_t file_id,
165 const MTPDeviceTaskHelper::GetFileInfoSuccessCallback& success_callback,
166 const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
167 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
168 MTPDeviceTaskHelper* task_helper =
169 GetDeviceTaskHelperForStorage(storage_name, read_only);
170 if (!task_helper)
171 return;
172 task_helper->GetFileInfo(file_id, success_callback, error_callback);
173 }
174
175 // Copies the contents of |device_file_path| to |snapshot_file_path|.
176 //
177 // Called on the UI thread to dispatch the request to the
178 // MediaTransferProtocolManager.
179 //
180 // |storage_name| specifies the name of the storage device.
181 // |read_only| specifies the mode of the storage device.
182 // |device_file_path| specifies the media device file path.
183 // |snapshot_file_path| specifies the platform path of the snapshot file.
184 // |file_size| specifies the number of bytes that will be written to the
185 // snapshot file.
186 // |success_callback| is called when the copy operation succeeds.
187 // |error_callback| is called when the copy operation fails.
188 // |success_callback| and |error_callback| runs on the IO thread.
189 void WriteDataIntoSnapshotFileOnUIThread(
190 const std::string& storage_name,
191 const bool read_only,
192 const SnapshotRequestInfo& request_info,
193 const base::File::Info& snapshot_file_info) {
194 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
195 MTPDeviceTaskHelper* task_helper =
196 GetDeviceTaskHelperForStorage(storage_name, read_only);
197 if (!task_helper)
198 return;
199 task_helper->WriteDataIntoSnapshotFile(request_info, snapshot_file_info);
200 }
201
202 // Copies the contents of |device_file_path| to |snapshot_file_path|.
203 //
204 // Called on the UI thread to dispatch the request to the
205 // MediaTransferProtocolManager.
206 //
207 // |storage_name| specifies the name of the storage device.
208 // |read_only| specifies the mode of the storage device.
209 // |request| is a struct containing details about the byte read request.
210 void ReadBytesOnUIThread(
211 const std::string& storage_name,
212 const bool read_only,
213 const MTPDeviceAsyncDelegate::ReadBytesRequest& request) {
214 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
215 MTPDeviceTaskHelper* task_helper =
216 GetDeviceTaskHelperForStorage(storage_name, read_only);
217 if (!task_helper)
218 return;
219 task_helper->ReadBytes(request);
220 }
221
222 // Renames |object_id| to |new_name|.
223 //
224 // |storage_name| specifies the name of the storage device.
225 // |read_only| specifies the mode of the storage device.
226 // |object_id| is an id of object to be renamed.
227 // |new_name| is new name of the object.
228 // |success_callback| is called when the object is renamed successfully.
229 // |error_callback| is called when it fails to rename the object.
230 // |success_callback| and |error_callback| runs on the IO thread.
231 void RenameObjectOnUIThread(
232 const std::string& storage_name,
233 const bool read_only,
234 const uint32_t object_id,
235 const std::string& new_name,
236 const MTPDeviceTaskHelper::RenameObjectSuccessCallback& success_callback,
237 const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
238 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
239 MTPDeviceTaskHelper* task_helper =
240 GetDeviceTaskHelperForStorage(storage_name, read_only);
241 if (!task_helper)
242 return;
243 task_helper->RenameObject(object_id, new_name, success_callback,
244 error_callback);
245 }
246
247 // Copies the file |source_file_descriptor| to |file_name| in |parent_id|.
248 //
249 // |storage_name| specifies the name of the storage device.
250 // |read_only| specifies the mode of the storage device.
251 // |source_file_descriptor| file descriptor of source file.
252 // |parent_id| object id of a target directory.
253 // |file_name| file name of a target file.
254 // |success_callback| is called when the file is copied successfully.
255 // |error_callback| is called when it fails to copy file.
256 // Since this method does not close the file descriptor, callbacks are
257 // responsible for closing it.
258 void CopyFileFromLocalOnUIThread(
259 const std::string& storage_name,
260 const bool read_only,
261 const int source_file_descriptor,
262 const uint32_t parent_id,
263 const std::string& file_name,
264 const MTPDeviceTaskHelper::CopyFileFromLocalSuccessCallback&
265 success_callback,
266 const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
267 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
268 MTPDeviceTaskHelper* task_helper =
269 GetDeviceTaskHelperForStorage(storage_name, read_only);
270 if (!task_helper)
271 return;
272 task_helper->CopyFileFromLocal(storage_name, source_file_descriptor,
273 parent_id, file_name, success_callback,
274 error_callback);
275 }
276
277 // Deletes |object_id|.
278 //
279 // Called on the UI thread to dispatch the request to the
280 // MediaTransferProtocolManager.
281 //
282 // |storage_name| specifies the name of the storage device.
283 // |read_only| specifies the mode of the storage device.
284 // |object_id| is the object to be deleted.
285 // |success_callback| is called when the object is deleted successfully.
286 // |error_callback| is called when it fails to delete the object.
287 // |success_callback| and |error_callback| runs on the IO thread.
288 void DeleteObjectOnUIThread(
289 const std::string storage_name,
290 const bool read_only,
291 const uint32_t object_id,
292 const MTPDeviceTaskHelper::DeleteObjectSuccessCallback success_callback,
293 const MTPDeviceTaskHelper::ErrorCallback error_callback) {
294 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
295 MTPDeviceTaskHelper* task_helper =
296 GetDeviceTaskHelperForStorage(storage_name, read_only);
297 if (!task_helper)
298 return;
299 task_helper->DeleteObject(object_id, success_callback, error_callback);
300 }
301
302 // Closes the device storage specified by the |storage_name| and destroys the
303 // MTPDeviceTaskHelper object associated with the device storage.
304 //
305 // Called on the UI thread to dispatch the request to the
306 // MediaTransferProtocolManager.
307 void CloseStorageAndDestroyTaskHelperOnUIThread(
308 const std::string& storage_name,
309 const bool read_only) {
310 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
311 MTPDeviceTaskHelper* task_helper =
312 GetDeviceTaskHelperForStorage(storage_name, read_only);
313 if (!task_helper)
314 return;
315 task_helper->CloseStorage();
316 MTPDeviceTaskHelperMapService::GetInstance()->DestroyDeviceTaskHelper(
317 storage_name, read_only);
318 }
319
320 // Opens |file_path| with |flags|. Returns the result as a pair.
321 // first is file descriptor.
322 // second is base::File::Error. This value is set as following.
323 // - When it succeeds to open a file descriptor, base::File::FILE_OK is set.
324 // - When |file_path| is a directory, base::File::FILE_ERROR_NOT_A_FILE is set.
325 // - When |file_path| does not exist, base::File::FILE_ERROR_NOT_FOUND is set.
326 // - For other error cases, base::File::FILE_ERROR_FAILED is set.
327 std::pair<int, base::File::Error> OpenFileDescriptor(const char* file_path,
328 const int flags) {
329 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
330
331 if (base::DirectoryExists(base::FilePath(file_path)))
332 return std::make_pair(-1, base::File::FILE_ERROR_NOT_A_FILE);
333 int file_descriptor = open(file_path, flags);
334 if (file_descriptor >= 0)
335 return std::make_pair(file_descriptor, base::File::FILE_OK);
336 if (errno == ENOENT)
337 return std::make_pair(file_descriptor, base::File::FILE_ERROR_NOT_FOUND);
338 return std::make_pair(file_descriptor, base::File::FILE_ERROR_FAILED);
339 }
340
341 // Closes |file_descriptor| on file thread.
342 void CloseFileDescriptor(const int file_descriptor) {
343 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
344
345 IGNORE_EINTR(close(file_descriptor));
346 }
347
348 // Deletes a temporary file |file_path|.
349 void DeleteTemporaryFile(const base::FilePath& file_path) {
350 content::BrowserThread::PostBlockingPoolTask(
351 FROM_HERE, base::Bind(base::IgnoreResult(base::DeleteFile), file_path,
352 false /* not recursive*/));
353 }
354
355 // A fake callback to be passed as CopyFileProgressCallback.
356 void FakeCopyFileProgressCallback(int64_t size) {}
357
358 } // namespace
359
360 MTPDeviceDelegateImplLinux::PendingTaskInfo::PendingTaskInfo(
361 const base::FilePath& path,
362 content::BrowserThread::ID thread_id,
363 const tracked_objects::Location& location,
364 const base::Closure& task)
365 : path(path),
366 thread_id(thread_id),
367 location(location),
368 task(task) {
369 }
370
371 MTPDeviceDelegateImplLinux::PendingTaskInfo::PendingTaskInfo(
372 const PendingTaskInfo& other) = default;
373
374 MTPDeviceDelegateImplLinux::PendingTaskInfo::~PendingTaskInfo() {
375 }
376
377 // Represents a file on the MTP device.
378 // Lives on the IO thread.
379 class MTPDeviceDelegateImplLinux::MTPFileNode {
380 public:
381 MTPFileNode(uint32_t file_id,
382 const std::string& file_name,
383 MTPFileNode* parent,
384 FileIdToMTPFileNodeMap* file_id_to_node_map);
385 ~MTPFileNode();
386
387 const MTPFileNode* GetChild(const std::string& name) const;
388
389 void EnsureChildExists(const std::string& name, uint32_t id);
390
391 // Clears all the children, except those in |children_to_keep|.
392 void ClearNonexistentChildren(
393 const std::set<std::string>& children_to_keep);
394
395 bool DeleteChild(uint32_t file_id);
396
397 bool HasChildren() const;
398
399 uint32_t file_id() const { return file_id_; }
400 const std::string& file_name() const { return file_name_; }
401 MTPFileNode* parent() { return parent_; }
402
403 private:
404 // Container for holding a node's children.
405 typedef base::ScopedPtrHashMap<std::string, std::unique_ptr<MTPFileNode>>
406 ChildNodes;
407
408 const uint32_t file_id_;
409 const std::string file_name_;
410
411 ChildNodes children_;
412 MTPFileNode* const parent_;
413 FileIdToMTPFileNodeMap* file_id_to_node_map_;
414
415 DISALLOW_COPY_AND_ASSIGN(MTPFileNode);
416 };
417
418 MTPDeviceDelegateImplLinux::MTPFileNode::MTPFileNode(
419 uint32_t file_id,
420 const std::string& file_name,
421 MTPFileNode* parent,
422 FileIdToMTPFileNodeMap* file_id_to_node_map)
423 : file_id_(file_id),
424 file_name_(file_name),
425 parent_(parent),
426 file_id_to_node_map_(file_id_to_node_map) {
427 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
428 DCHECK(file_id_to_node_map_);
429 DCHECK(!base::ContainsKey(*file_id_to_node_map_, file_id_));
430 (*file_id_to_node_map_)[file_id_] = this;
431 }
432
433 MTPDeviceDelegateImplLinux::MTPFileNode::~MTPFileNode() {
434 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
435 size_t erased = file_id_to_node_map_->erase(file_id_);
436 DCHECK_EQ(1U, erased);
437 }
438
439 const MTPDeviceDelegateImplLinux::MTPFileNode*
440 MTPDeviceDelegateImplLinux::MTPFileNode::GetChild(
441 const std::string& name) const {
442 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
443 return children_.get(name);
444 }
445
446 void MTPDeviceDelegateImplLinux::MTPFileNode::EnsureChildExists(
447 const std::string& name,
448 uint32_t id) {
449 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
450 const MTPFileNode* child = GetChild(name);
451 if (child && child->file_id() == id)
452 return;
453
454 children_.set(name, base::WrapUnique(new MTPFileNode(id, name, this,
455 file_id_to_node_map_)));
456 }
457
458 void MTPDeviceDelegateImplLinux::MTPFileNode::ClearNonexistentChildren(
459 const std::set<std::string>& children_to_keep) {
460 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
461 std::set<std::string> children_to_erase;
462 for (ChildNodes::const_iterator it = children_.begin();
463 it != children_.end(); ++it) {
464 if (base::ContainsKey(children_to_keep, it->first))
465 continue;
466 children_to_erase.insert(it->first);
467 }
468 for (std::set<std::string>::iterator it = children_to_erase.begin();
469 it != children_to_erase.end(); ++it) {
470 children_.take_and_erase(*it);
471 }
472 }
473
474 bool MTPDeviceDelegateImplLinux::MTPFileNode::DeleteChild(uint32_t file_id) {
475 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
476 for (ChildNodes::iterator it = children_.begin();
477 it != children_.end(); ++it) {
478 if (it->second->file_id() == file_id) {
479 DCHECK(!it->second->HasChildren());
480 children_.erase(it);
481 return true;
482 }
483 }
484 return false;
485 }
486
487 bool MTPDeviceDelegateImplLinux::MTPFileNode::HasChildren() const {
488 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
489 return children_.size() > 0;
490 }
491
492 MTPDeviceDelegateImplLinux::MTPDeviceDelegateImplLinux(
493 const std::string& device_location,
494 const bool read_only)
495 : init_state_(UNINITIALIZED),
496 task_in_progress_(false),
497 device_path_(device_location),
498 read_only_(read_only),
499 root_node_(new MTPFileNode(mtpd::kRootFileId,
500 "", // Root node has no name.
501 NULL, // And no parent node.
502 &file_id_to_node_map_)),
503 weak_ptr_factory_(this) {
504 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
505 DCHECK(!device_path_.empty());
506 base::RemoveChars(device_location, kRootPath, &storage_name_);
507 DCHECK(!storage_name_.empty());
508 }
509
510 MTPDeviceDelegateImplLinux::~MTPDeviceDelegateImplLinux() {
511 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
512 }
513
514 void MTPDeviceDelegateImplLinux::CreateDirectory(
515 const base::FilePath& directory_path,
516 const bool exclusive,
517 const bool recursive,
518 const CreateDirectorySuccessCallback& success_callback,
519 const ErrorCallback& error_callback) {
520 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
521 DCHECK(!directory_path.empty());
522
523 // If |directory_path| is not the path in this device, fails with error.
524 if (!device_path_.IsParent(directory_path)) {
525 error_callback.Run(base::File::FILE_ERROR_FAILED);
526 return;
527 }
528
529 // Decomposes |directory_path| to components. CreateDirectoryInternal creates
530 // directories by reading |components| from back.
531 std::vector<base::FilePath> components;
532 if (recursive) {
533 for (base::FilePath path = directory_path; path != device_path_;
534 path = path.DirName()) {
535 components.push_back(path);
536 }
537 } else {
538 components.push_back(directory_path);
539 }
540
541 const base::Closure closure =
542 base::Bind(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal,
543 weak_ptr_factory_.GetWeakPtr(), components, exclusive,
544 success_callback, error_callback);
545 EnsureInitAndRunTask(PendingTaskInfo(
546 directory_path, content::BrowserThread::IO, FROM_HERE, closure));
547 }
548
549 void MTPDeviceDelegateImplLinux::GetFileInfo(
550 const base::FilePath& file_path,
551 const GetFileInfoSuccessCallback& success_callback,
552 const ErrorCallback& error_callback) {
553 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
554 DCHECK(!file_path.empty());
555
556 // If a ReadDirectory operation is in progress, the file info may already be
557 // cached.
558 FileInfoCache::const_iterator it = file_info_cache_.find(file_path);
559 if (it != file_info_cache_.end()) {
560 // TODO(thestig): This code is repeated in several places. Combine them.
561 // e.g. c/b/media_galleries/win/mtp_device_operations_util.cc
562 const MTPDeviceTaskHelper::MTPEntry& cached_file_entry = it->second;
563 success_callback.Run(cached_file_entry.file_info);
564 return;
565 }
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));
576 }
577
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));
594 }
595
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));
615 }
616
617 bool MTPDeviceDelegateImplLinux::IsStreaming() {
618 return true;
619 }
620
621 void MTPDeviceDelegateImplLinux::ReadBytes(
622 const base::FilePath& device_file_path,
623 const scoped_refptr<net::IOBuffer>& buf,
624 int64_t 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 = base::Bind(
631 &MTPDeviceDelegateImplLinux::ReadBytesInternal,
632 weak_ptr_factory_.GetWeakPtr(), device_file_path, base::RetainedRef(buf),
633 offset, buf_len, success_callback, error_callback);
634 EnsureInitAndRunTask(PendingTaskInfo(device_file_path,
635 content::BrowserThread::IO,
636 FROM_HERE,
637 closure));
638 }
639
640 bool MTPDeviceDelegateImplLinux::IsReadOnly() const {
641 return read_only_;
642 }
643
644 void MTPDeviceDelegateImplLinux::CopyFileLocal(
645 const base::FilePath& source_file_path,
646 const base::FilePath& device_file_path,
647 const CreateTemporaryFileCallback& create_temporary_file_callback,
648 const CopyFileProgressCallback& progress_callback,
649 const CopyFileLocalSuccessCallback& success_callback,
650 const ErrorCallback& error_callback) {
651 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
652 DCHECK(!source_file_path.empty());
653 DCHECK(!device_file_path.empty());
654
655 // Create a temporary file for creating a copy of source file on local.
656 content::BrowserThread::PostTaskAndReplyWithResult(
657 content::BrowserThread::FILE, FROM_HERE, create_temporary_file_callback,
658 base::Bind(
659 &MTPDeviceDelegateImplLinux::OnDidCreateTemporaryFileToCopyFileLocal,
660 weak_ptr_factory_.GetWeakPtr(), source_file_path, device_file_path,
661 progress_callback, success_callback, error_callback));
662 }
663
664 void MTPDeviceDelegateImplLinux::MoveFileLocal(
665 const base::FilePath& source_file_path,
666 const base::FilePath& device_file_path,
667 const CreateTemporaryFileCallback& create_temporary_file_callback,
668 const MoveFileLocalSuccessCallback& success_callback,
669 const ErrorCallback& error_callback) {
670 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
671 DCHECK(!source_file_path.empty());
672 DCHECK(!device_file_path.empty());
673
674 // Get file info to move file on local.
675 const GetFileInfoSuccessCallback success_callback_wrapper = base::Bind(
676 &MTPDeviceDelegateImplLinux::MoveFileLocalInternal,
677 weak_ptr_factory_.GetWeakPtr(), source_file_path, device_file_path,
678 create_temporary_file_callback, success_callback, error_callback);
679 const base::Closure closure =
680 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
681 weak_ptr_factory_.GetWeakPtr(), source_file_path,
682 success_callback_wrapper, error_callback);
683 EnsureInitAndRunTask(PendingTaskInfo(
684 source_file_path, content::BrowserThread::IO, FROM_HERE, closure));
685 }
686
687 void MTPDeviceDelegateImplLinux::CopyFileFromLocal(
688 const base::FilePath& source_file_path,
689 const base::FilePath& device_file_path,
690 const CopyFileFromLocalSuccessCallback& success_callback,
691 const ErrorCallback& error_callback) {
692 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
693 DCHECK(!source_file_path.empty());
694 DCHECK(!device_file_path.empty());
695
696 // Get file info of destination file path.
697 const GetFileInfoSuccessCallback success_callback_wrapper = base::Bind(
698 &MTPDeviceDelegateImplLinux::OnDidGetDestFileInfoToCopyFileFromLocal,
699 weak_ptr_factory_.GetWeakPtr(), error_callback);
700 const ErrorCallback error_callback_wrapper = base::Bind(
701 &MTPDeviceDelegateImplLinux::OnGetDestFileInfoErrorToCopyFileFromLocal,
702 weak_ptr_factory_.GetWeakPtr(), source_file_path, device_file_path,
703 success_callback, error_callback);
704 const base::Closure closure =
705 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
706 weak_ptr_factory_.GetWeakPtr(), device_file_path,
707 success_callback_wrapper, error_callback_wrapper);
708 EnsureInitAndRunTask(PendingTaskInfo(
709 device_file_path, content::BrowserThread::IO, FROM_HERE, closure));
710 }
711
712 void MTPDeviceDelegateImplLinux::DeleteFile(
713 const base::FilePath& file_path,
714 const DeleteFileSuccessCallback& success_callback,
715 const ErrorCallback& error_callback) {
716 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
717 DCHECK(!file_path.empty());
718
719 const GetFileInfoSuccessCallback& success_callback_wrapper =
720 base::Bind(&MTPDeviceDelegateImplLinux::DeleteFileInternal,
721 weak_ptr_factory_.GetWeakPtr(), file_path, success_callback,
722 error_callback);
723
724 const base::Closure closure =
725 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
726 weak_ptr_factory_.GetWeakPtr(), file_path,
727 success_callback_wrapper, error_callback);
728 EnsureInitAndRunTask(PendingTaskInfo(file_path, content::BrowserThread::IO,
729 FROM_HERE, closure));
730 }
731
732 void MTPDeviceDelegateImplLinux::DeleteDirectory(
733 const base::FilePath& file_path,
734 const DeleteDirectorySuccessCallback& success_callback,
735 const ErrorCallback& error_callback) {
736 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
737 DCHECK(!file_path.empty());
738
739 const GetFileInfoSuccessCallback& success_callback_wrapper =
740 base::Bind(&MTPDeviceDelegateImplLinux::DeleteDirectoryInternal,
741 weak_ptr_factory_.GetWeakPtr(), file_path, success_callback,
742 error_callback);
743
744 const base::Closure closure =
745 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
746 weak_ptr_factory_.GetWeakPtr(), file_path,
747 success_callback_wrapper, error_callback);
748 EnsureInitAndRunTask(PendingTaskInfo(file_path, content::BrowserThread::IO,
749 FROM_HERE, closure));
750 }
751
752 void MTPDeviceDelegateImplLinux::AddWatcher(
753 const GURL& origin,
754 const base::FilePath& file_path,
755 const bool recursive,
756 const storage::WatcherManager::StatusCallback& callback,
757 const storage::WatcherManager::NotificationCallback&
758 notification_callback) {
759 if (recursive) {
760 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
761 return;
762 }
763
764 const auto it = subscribers_.find(file_path);
765 if (it != subscribers_.end()) {
766 // Adds to existing origin callback map.
767 if (ContainsKey(it->second, origin)) {
768 callback.Run(base::File::FILE_ERROR_EXISTS);
769 return;
770 }
771
772 it->second.insert(std::make_pair(origin, notification_callback));
773 } else {
774 // Creates new origin callback map.
775 OriginNotificationCallbackMap callback_map;
776 callback_map.insert(std::make_pair(origin, notification_callback));
777 subscribers_.insert(std::make_pair(file_path, callback_map));
778 }
779
780 callback.Run(base::File::FILE_OK);
781 }
782
783 void MTPDeviceDelegateImplLinux::RemoveWatcher(
784 const GURL& origin,
785 const base::FilePath& file_path,
786 const bool recursive,
787 const storage::WatcherManager::StatusCallback& callback) {
788 if (recursive) {
789 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
790 return;
791 }
792
793 const auto it = subscribers_.find(file_path);
794 if (it == subscribers_.end()) {
795 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
796 return;
797 }
798
799 if (it->second.erase(origin) == 0) {
800 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
801 return;
802 }
803
804 if (it->second.empty())
805 subscribers_.erase(it);
806
807 callback.Run(base::File::FILE_OK);
808 }
809
810 void MTPDeviceDelegateImplLinux::NotifyFileChange(
811 const base::FilePath& file_path,
812 const storage::WatcherManager::ChangeType change_type) {
813 const auto it = subscribers_.find(file_path);
814 if (it != subscribers_.end()) {
815 for (const auto& origin_callback : it->second) {
816 origin_callback.second.Run(change_type);
817 }
818 }
819 }
820
821 void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() {
822 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
823 // To cancel all the pending tasks, destroy the MTPDeviceTaskHelper object.
824 content::BrowserThread::PostTask(
825 content::BrowserThread::UI,
826 FROM_HERE,
827 base::Bind(&CloseStorageAndDestroyTaskHelperOnUIThread,
828 storage_name_,
829 read_only_));
830 delete this;
831 }
832
833 void MTPDeviceDelegateImplLinux::GetFileInfoInternal(
834 const base::FilePath& file_path,
835 const GetFileInfoSuccessCallback& success_callback,
836 const ErrorCallback& error_callback) {
837 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
838
839 uint32_t file_id;
840 if (CachedPathToId(file_path, &file_id)) {
841 GetFileInfoSuccessCallback success_callback_wrapper =
842 base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfo,
843 weak_ptr_factory_.GetWeakPtr(),
844 success_callback);
845 ErrorCallback error_callback_wrapper =
846 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
847 weak_ptr_factory_.GetWeakPtr(),
848 error_callback,
849 file_id);
850
851
852 base::Closure closure = base::Bind(&GetFileInfoOnUIThread,
853 storage_name_,
854 read_only_,
855 file_id,
856 success_callback_wrapper,
857 error_callback_wrapper);
858 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
859 content::BrowserThread::UI,
860 FROM_HERE,
861 closure));
862 } else {
863 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
864 }
865 PendingRequestDone();
866 }
867
868 void MTPDeviceDelegateImplLinux::CreateDirectoryInternal(
869 const std::vector<base::FilePath>& components,
870 const bool exclusive,
871 const CreateDirectorySuccessCallback& success_callback,
872 const ErrorCallback& error_callback) {
873 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
874
875 const base::FilePath current_component = components.back();
876 std::vector<base::FilePath> other_components = components;
877 other_components.pop_back();
878
879 if (other_components.empty()) {
880 // Either we reached the last component in the recursive case, or this is
881 // the non-recursive case.
882 uint32_t parent_id;
883 if (CachedPathToId(current_component.DirName(), &parent_id)) {
884 const base::Closure closure =
885 base::Bind(&MTPDeviceDelegateImplLinux::CreateSingleDirectory,
886 weak_ptr_factory_.GetWeakPtr(), current_component,
887 exclusive, success_callback, error_callback);
888 EnsureInitAndRunTask(PendingTaskInfo(
889 base::FilePath(), content::BrowserThread::IO, FROM_HERE, closure));
890 } else {
891 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
892 }
893 } else {
894 // Ensures that parent directories are created for recursive case.
895 uint32_t directory_id;
896 if (CachedPathToId(current_component, &directory_id)) {
897 // Parent directory |current_component| already exists, continue creating
898 // directories.
899 const base::Closure closure =
900 base::Bind(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal,
901 weak_ptr_factory_.GetWeakPtr(), other_components,
902 exclusive, success_callback, error_callback);
903 EnsureInitAndRunTask(PendingTaskInfo(
904 base::FilePath(), content::BrowserThread::IO, FROM_HERE, closure));
905 } else {
906 // If parent directory |current_component| does not exist, create it.
907 const CreateDirectorySuccessCallback success_callback_wrapper =
908 base::Bind(&MTPDeviceDelegateImplLinux::
909 OnDidCreateParentDirectoryToCreateDirectory,
910 weak_ptr_factory_.GetWeakPtr(), current_component,
911 other_components, exclusive, success_callback,
912 error_callback);
913 // Wraps error callback to return all errors of creating parent
914 // directories as FILE_ERROR_FAILED.
915 const ErrorCallback error_callback_wrapper =
916 base::Bind(&MTPDeviceDelegateImplLinux::
917 OnCreateParentDirectoryErrorToCreateDirectory,
918 weak_ptr_factory_.GetWeakPtr(), error_callback);
919 const base::Closure closure =
920 base::Bind(&MTPDeviceDelegateImplLinux::CreateSingleDirectory,
921 weak_ptr_factory_.GetWeakPtr(), current_component,
922 false /* not exclusive */, success_callback_wrapper,
923 error_callback_wrapper);
924 EnsureInitAndRunTask(PendingTaskInfo(
925 base::FilePath(), content::BrowserThread::IO, FROM_HERE, closure));
926 }
927 }
928
929 PendingRequestDone();
930 }
931
932 void MTPDeviceDelegateImplLinux::ReadDirectoryInternal(
933 const base::FilePath& root,
934 const ReadDirectorySuccessCallback& success_callback,
935 const ErrorCallback& error_callback) {
936 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
937
938 uint32_t dir_id;
939 if (CachedPathToId(root, &dir_id)) {
940 GetFileInfoSuccessCallback success_callback_wrapper =
941 base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory,
942 weak_ptr_factory_.GetWeakPtr(),
943 dir_id,
944 success_callback,
945 error_callback);
946 ErrorCallback error_callback_wrapper =
947 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
948 weak_ptr_factory_.GetWeakPtr(),
949 error_callback,
950 dir_id);
951 base::Closure closure = base::Bind(&GetFileInfoOnUIThread,
952 storage_name_,
953 read_only_,
954 dir_id,
955 success_callback_wrapper,
956 error_callback_wrapper);
957 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
958 content::BrowserThread::UI,
959 FROM_HERE,
960 closure));
961 } else {
962 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
963 }
964 PendingRequestDone();
965 }
966
967 void MTPDeviceDelegateImplLinux::CreateSnapshotFileInternal(
968 const base::FilePath& device_file_path,
969 const base::FilePath& local_path,
970 const CreateSnapshotFileSuccessCallback& success_callback,
971 const ErrorCallback& error_callback) {
972 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
973
974 uint32_t file_id;
975 if (CachedPathToId(device_file_path, &file_id)) {
976 std::unique_ptr<SnapshotRequestInfo> request_info(new SnapshotRequestInfo(
977 file_id, local_path, success_callback, error_callback));
978 GetFileInfoSuccessCallback success_callback_wrapper =
979 base::Bind(
980 &MTPDeviceDelegateImplLinux::OnDidGetFileInfoToCreateSnapshotFile,
981 weak_ptr_factory_.GetWeakPtr(),
982 base::Passed(&request_info));
983 ErrorCallback error_callback_wrapper =
984 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
985 weak_ptr_factory_.GetWeakPtr(),
986 error_callback,
987 file_id);
988 base::Closure closure = base::Bind(&GetFileInfoOnUIThread,
989 storage_name_,
990 read_only_,
991 file_id,
992 success_callback_wrapper,
993 error_callback_wrapper);
994 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
995 content::BrowserThread::UI,
996 FROM_HERE,
997 closure));
998 } else {
999 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
1000 }
1001 PendingRequestDone();
1002 }
1003
1004 void MTPDeviceDelegateImplLinux::ReadBytesInternal(
1005 const base::FilePath& device_file_path,
1006 net::IOBuffer* buf,
1007 int64_t offset,
1008 int buf_len,
1009 const ReadBytesSuccessCallback& success_callback,
1010 const ErrorCallback& error_callback) {
1011 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1012
1013 uint32_t file_id;
1014 if (CachedPathToId(device_file_path, &file_id)) {
1015 ReadBytesRequest request(
1016 file_id, buf, offset, buf_len,
1017 base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadBytes,
1018 weak_ptr_factory_.GetWeakPtr(),
1019 success_callback),
1020 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
1021 weak_ptr_factory_.GetWeakPtr(),
1022 error_callback,
1023 file_id));
1024
1025 base::Closure closure =
1026 base::Bind(&ReadBytesOnUIThread, storage_name_, read_only_, request);
1027 EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
1028 content::BrowserThread::UI,
1029 FROM_HERE,
1030 closure));
1031 } else {
1032 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
1033 }
1034 PendingRequestDone();
1035 }
1036
1037 void MTPDeviceDelegateImplLinux::MoveFileLocalInternal(
1038 const base::FilePath& source_file_path,
1039 const base::FilePath& device_file_path,
1040 const CreateTemporaryFileCallback& create_temporary_file_callback,
1041 const MoveFileLocalSuccessCallback& success_callback,
1042 const ErrorCallback& error_callback,
1043 const base::File::Info& source_file_info) {
1044 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1045
1046 if (source_file_info.is_directory) {
1047 error_callback.Run(base::File::FILE_ERROR_NOT_A_FILE);
1048 return;
1049 }
1050
1051 if (source_file_path.DirName() == device_file_path.DirName()) {
1052 // If a file is moved in a same directory, rename the file.
1053 uint32_t file_id;
1054 if (CachedPathToId(source_file_path, &file_id)) {
1055 const MTPDeviceTaskHelper::RenameObjectSuccessCallback
1056 success_callback_wrapper = base::Bind(
1057 &MTPDeviceDelegateImplLinux::OnDidMoveFileLocalWithRename,
1058 weak_ptr_factory_.GetWeakPtr(), success_callback,
1059 source_file_path, file_id);
1060 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper =
1061 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
1062 weak_ptr_factory_.GetWeakPtr(), error_callback, file_id);
1063 const base::Closure closure =
1064 base::Bind(&RenameObjectOnUIThread, storage_name_, read_only_,
1065 file_id, device_file_path.BaseName().value(),
1066 success_callback_wrapper, error_callback_wrapper);
1067 EnsureInitAndRunTask(PendingTaskInfo(
1068 base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
1069 } else {
1070 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
1071 }
1072 } else {
1073 // If a file is moved to a different directory, create a copy to the
1074 // destination path, and remove source file.
1075 const CopyFileLocalSuccessCallback& success_callback_wrapper =
1076 base::Bind(&MTPDeviceDelegateImplLinux::DeleteFileInternal,
1077 weak_ptr_factory_.GetWeakPtr(), source_file_path,
1078 success_callback, error_callback, source_file_info);
1079 // TODO(yawano): Avoid to call external method from internal code.
1080 CopyFileLocal(source_file_path, device_file_path,
1081 create_temporary_file_callback,
1082 base::Bind(&FakeCopyFileProgressCallback),
1083 success_callback_wrapper, error_callback);
1084 }
1085 }
1086
1087 void MTPDeviceDelegateImplLinux::OnDidOpenFDToCopyFileFromLocal(
1088 const base::FilePath& device_file_path,
1089 const CopyFileFromLocalSuccessCallback& success_callback,
1090 const ErrorCallback& error_callback,
1091 const std::pair<int, base::File::Error>& open_fd_result) {
1092 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1093
1094 if (open_fd_result.second != base::File::FILE_OK) {
1095 error_callback.Run(open_fd_result.second);
1096 return;
1097 }
1098
1099 const int source_file_descriptor = open_fd_result.first;
1100 uint32_t parent_id;
1101 if (CachedPathToId(device_file_path.DirName(), &parent_id)) {
1102 CopyFileFromLocalSuccessCallback success_callback_wrapper =
1103 base::Bind(&MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocal,
1104 weak_ptr_factory_.GetWeakPtr(), success_callback,
1105 device_file_path, source_file_descriptor);
1106
1107 ErrorCallback error_callback_wrapper = base::Bind(
1108 &MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError,
1109 weak_ptr_factory_.GetWeakPtr(), error_callback, source_file_descriptor);
1110
1111 base::Closure closure = base::Bind(&CopyFileFromLocalOnUIThread,
1112 storage_name_,
1113 read_only_,
1114 source_file_descriptor,
1115 parent_id,
1116 device_file_path.BaseName().value(),
1117 success_callback_wrapper,
1118 error_callback_wrapper);
1119
1120 EnsureInitAndRunTask(PendingTaskInfo(
1121 base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
1122 } else {
1123 HandleCopyFileFromLocalError(error_callback, source_file_descriptor,
1124 base::File::FILE_ERROR_NOT_FOUND);
1125 }
1126 }
1127
1128 void MTPDeviceDelegateImplLinux::DeleteFileInternal(
1129 const base::FilePath& file_path,
1130 const DeleteFileSuccessCallback& success_callback,
1131 const ErrorCallback& error_callback,
1132 const base::File::Info& file_info) {
1133 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1134
1135 if (file_info.is_directory) {
1136 error_callback.Run(base::File::FILE_ERROR_NOT_A_FILE);
1137 } else {
1138 uint32_t file_id;
1139 if (CachedPathToId(file_path, &file_id))
1140 RunDeleteObjectOnUIThread(file_path, file_id, success_callback,
1141 error_callback);
1142 else
1143 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
1144 }
1145 }
1146
1147 void MTPDeviceDelegateImplLinux::DeleteDirectoryInternal(
1148 const base::FilePath& file_path,
1149 const DeleteDirectorySuccessCallback& success_callback,
1150 const ErrorCallback& error_callback,
1151 const base::File::Info& file_info) {
1152 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1153
1154 if (!file_info.is_directory) {
1155 error_callback.Run(base::File::FILE_ERROR_NOT_A_DIRECTORY);
1156 return;
1157 }
1158
1159 uint32_t directory_id;
1160 if (!CachedPathToId(file_path, &directory_id)) {
1161 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
1162 return;
1163 }
1164
1165 // Checks the cache first. If it has children in cache, the directory cannot
1166 // be empty.
1167 FileIdToMTPFileNodeMap::const_iterator it =
1168 file_id_to_node_map_.find(directory_id);
1169 if (it != file_id_to_node_map_.end() && it->second->HasChildren()) {
1170 error_callback.Run(base::File::FILE_ERROR_NOT_EMPTY);
1171 return;
1172 }
1173
1174 // Since the directory can contain a file even if the cache returns it as
1175 // empty, read the directory and confirm the directory is actually empty.
1176 const MTPDeviceTaskHelper::ReadDirectorySuccessCallback
1177 success_callback_wrapper = base::Bind(
1178 &MTPDeviceDelegateImplLinux::OnDidReadDirectoryToDeleteDirectory,
1179 weak_ptr_factory_.GetWeakPtr(), file_path, directory_id,
1180 success_callback, error_callback);
1181 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper =
1182 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
1183 weak_ptr_factory_.GetWeakPtr(), error_callback, directory_id);
1184 const base::Closure closure = base::Bind(
1185 &ReadDirectoryOnUIThread, storage_name_, read_only_, directory_id,
1186 1 /* max_size */, success_callback_wrapper, error_callback_wrapper);
1187 EnsureInitAndRunTask(PendingTaskInfo(
1188 base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
1189 }
1190
1191 void MTPDeviceDelegateImplLinux::CreateSingleDirectory(
1192 const base::FilePath& directory_path,
1193 const bool exclusive,
1194 const CreateDirectorySuccessCallback& success_callback,
1195 const ErrorCallback& error_callback) {
1196 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1197
1198 const GetFileInfoSuccessCallback success_callback_wrapper = base::Bind(
1199 &MTPDeviceDelegateImplLinux::OnPathAlreadyExistsForCreateSingleDirectory,
1200 weak_ptr_factory_.GetWeakPtr(), exclusive, success_callback,
1201 error_callback);
1202 const ErrorCallback error_callback_wrapper = base::Bind(
1203 &MTPDeviceDelegateImplLinux::OnPathDoesNotExistForCreateSingleDirectory,
1204 weak_ptr_factory_.GetWeakPtr(), directory_path, success_callback,
1205 error_callback);
1206 const base::Closure closure =
1207 base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
1208 weak_ptr_factory_.GetWeakPtr(), directory_path,
1209 success_callback_wrapper, error_callback_wrapper);
1210 EnsureInitAndRunTask(PendingTaskInfo(
1211 base::FilePath(), content::BrowserThread::IO, FROM_HERE, closure));
1212 PendingRequestDone();
1213 }
1214
1215 void MTPDeviceDelegateImplLinux::OnDidReadDirectoryToCreateDirectory(
1216 const std::vector<base::FilePath>& components,
1217 const bool exclusive,
1218 const CreateDirectorySuccessCallback& success_callback,
1219 const ErrorCallback& error_callback,
1220 const storage::AsyncFileUtil::EntryList& /* entries */,
1221 const bool has_more) {
1222 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1223
1224 if (has_more)
1225 return; // Wait until all entries have been read.
1226
1227 const base::Closure closure =
1228 base::Bind(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal,
1229 weak_ptr_factory_.GetWeakPtr(), components, exclusive,
1230 success_callback, error_callback);
1231 EnsureInitAndRunTask(PendingTaskInfo(
1232 base::FilePath(), content::BrowserThread::IO, FROM_HERE, closure));
1233 }
1234
1235 void MTPDeviceDelegateImplLinux::OnDidReadDirectoryToDeleteDirectory(
1236 const base::FilePath& directory_path,
1237 const uint32_t directory_id,
1238 const DeleteDirectorySuccessCallback& success_callback,
1239 const ErrorCallback& error_callback,
1240 const MTPDeviceTaskHelper::MTPEntries& entries,
1241 const bool has_more) {
1242 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1243 DCHECK(!has_more);
1244
1245 if (entries.size() > 0) {
1246 error_callback.Run(base::File::FILE_ERROR_NOT_EMPTY);
1247 } else {
1248 RunDeleteObjectOnUIThread(directory_path, directory_id, success_callback,
1249 error_callback);
1250 }
1251
1252 PendingRequestDone();
1253 }
1254
1255 void MTPDeviceDelegateImplLinux::RunDeleteObjectOnUIThread(
1256 const base::FilePath& object_path,
1257 const uint32_t object_id,
1258 const DeleteObjectSuccessCallback& success_callback,
1259 const ErrorCallback& error_callback) {
1260 const MTPDeviceTaskHelper::DeleteObjectSuccessCallback
1261 success_callback_wrapper =
1262 base::Bind(&MTPDeviceDelegateImplLinux::OnDidDeleteObject,
1263 weak_ptr_factory_.GetWeakPtr(), object_path, object_id,
1264 success_callback);
1265
1266 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper =
1267 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeleteFileOrDirectoryError,
1268 weak_ptr_factory_.GetWeakPtr(), error_callback);
1269
1270 const base::Closure closure =
1271 base::Bind(&DeleteObjectOnUIThread, storage_name_, read_only_, object_id,
1272 success_callback_wrapper, error_callback_wrapper);
1273 EnsureInitAndRunTask(PendingTaskInfo(
1274 base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
1275 }
1276
1277 void MTPDeviceDelegateImplLinux::EnsureInitAndRunTask(
1278 const PendingTaskInfo& task_info) {
1279 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1280 if ((init_state_ == INITIALIZED) && !task_in_progress_) {
1281 RunTask(task_info);
1282 return;
1283 }
1284
1285 // Only *Internal functions have empty paths. Since they are the continuation
1286 // of the current running task, they get to cut in line.
1287 if (task_info.path.empty())
1288 pending_tasks_.push_front(task_info);
1289 else
1290 pending_tasks_.push_back(task_info);
1291
1292 if (init_state_ == UNINITIALIZED) {
1293 init_state_ = PENDING_INIT;
1294 task_in_progress_ = true;
1295 content::BrowserThread::PostTask(
1296 content::BrowserThread::UI, FROM_HERE,
1297 base::Bind(&OpenStorageOnUIThread, storage_name_, read_only_,
1298 base::Bind(&MTPDeviceDelegateImplLinux::OnInitCompleted,
1299 weak_ptr_factory_.GetWeakPtr())));
1300 }
1301 }
1302
1303 void MTPDeviceDelegateImplLinux::RunTask(const PendingTaskInfo& task_info) {
1304 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1305 DCHECK_EQ(INITIALIZED, init_state_);
1306 DCHECK(!task_in_progress_);
1307 task_in_progress_ = true;
1308
1309 bool need_to_check_cache = !task_info.path.empty();
1310 if (need_to_check_cache) {
1311 base::FilePath uncached_path =
1312 NextUncachedPathComponent(task_info.path, task_info.cached_path);
1313 if (!uncached_path.empty()) {
1314 // Save the current task and do a cache lookup first.
1315 pending_tasks_.push_front(task_info);
1316 FillFileCache(uncached_path);
1317 return;
1318 }
1319 }
1320
1321 content::BrowserThread::PostTask(task_info.thread_id,
1322 task_info.location,
1323 task_info.task);
1324 }
1325
1326 void MTPDeviceDelegateImplLinux::WriteDataIntoSnapshotFile(
1327 const base::File::Info& file_info) {
1328 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1329 DCHECK(current_snapshot_request_info_.get());
1330 DCHECK_GT(file_info.size, 0);
1331 DCHECK(task_in_progress_);
1332 SnapshotRequestInfo request_info(
1333 current_snapshot_request_info_->file_id,
1334 current_snapshot_request_info_->snapshot_file_path,
1335 base::Bind(
1336 &MTPDeviceDelegateImplLinux::OnDidWriteDataIntoSnapshotFile,
1337 weak_ptr_factory_.GetWeakPtr()),
1338 base::Bind(
1339 &MTPDeviceDelegateImplLinux::OnWriteDataIntoSnapshotFileError,
1340 weak_ptr_factory_.GetWeakPtr()));
1341
1342 base::Closure task_closure = base::Bind(&WriteDataIntoSnapshotFileOnUIThread,
1343 storage_name_,
1344 read_only_,
1345 request_info,
1346 file_info);
1347 content::BrowserThread::PostTask(content::BrowserThread::UI,
1348 FROM_HERE,
1349 task_closure);
1350 }
1351
1352 void MTPDeviceDelegateImplLinux::PendingRequestDone() {
1353 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1354 DCHECK(task_in_progress_);
1355 task_in_progress_ = false;
1356 ProcessNextPendingRequest();
1357 }
1358
1359 void MTPDeviceDelegateImplLinux::ProcessNextPendingRequest() {
1360 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1361 DCHECK(!task_in_progress_);
1362 if (pending_tasks_.empty())
1363 return;
1364
1365 PendingTaskInfo task_info = pending_tasks_.front();
1366 pending_tasks_.pop_front();
1367 RunTask(task_info);
1368 }
1369
1370 void MTPDeviceDelegateImplLinux::OnInitCompleted(bool succeeded) {
1371 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1372 init_state_ = succeeded ? INITIALIZED : UNINITIALIZED;
1373 PendingRequestDone();
1374 }
1375
1376 void MTPDeviceDelegateImplLinux::OnDidGetFileInfo(
1377 const GetFileInfoSuccessCallback& success_callback,
1378 const base::File::Info& file_info) {
1379 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1380 success_callback.Run(file_info);
1381 PendingRequestDone();
1382 }
1383
1384 void MTPDeviceDelegateImplLinux::OnPathAlreadyExistsForCreateSingleDirectory(
1385 const bool exclusive,
1386 const CreateDirectorySuccessCallback& success_callback,
1387 const ErrorCallback& error_callback,
1388 const base::File::Info& file_info) {
1389 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1390
1391 if (!file_info.is_directory || exclusive)
1392 error_callback.Run(base::File::FILE_ERROR_EXISTS);
1393 else
1394 success_callback.Run();
1395 }
1396
1397 void MTPDeviceDelegateImplLinux::OnPathDoesNotExistForCreateSingleDirectory(
1398 const base::FilePath& directory_path,
1399 const CreateDirectorySuccessCallback& success_callback,
1400 const ErrorCallback& error_callback,
1401 const base::File::Error error) {
1402 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1403
1404 if (error != base::File::FILE_ERROR_NOT_FOUND) {
1405 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
1406 return;
1407 }
1408
1409 uint32_t parent_id;
1410 if (!CachedPathToId(directory_path.DirName(), &parent_id)) {
1411 error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
1412 return;
1413 }
1414
1415 const MTPDeviceTaskHelper::CreateDirectorySuccessCallback
1416 success_callback_wrapper = base::Bind(
1417 &MTPDeviceDelegateImplLinux::OnDidCreateSingleDirectory,
1418 weak_ptr_factory_.GetWeakPtr(), directory_path, success_callback);
1419 const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper =
1420 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
1421 weak_ptr_factory_.GetWeakPtr(), error_callback, parent_id);
1422 const base::Closure closure =
1423 base::Bind(&CreateDirectoryOnUIThread, storage_name_, read_only_,
1424 parent_id, directory_path.BaseName().value(),
1425 success_callback_wrapper, error_callback_wrapper);
1426 EnsureInitAndRunTask(PendingTaskInfo(
1427 base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
1428 }
1429
1430 void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory(
1431 uint32_t dir_id,
1432 const ReadDirectorySuccessCallback& success_callback,
1433 const ErrorCallback& error_callback,
1434 const base::File::Info& file_info) {
1435 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1436 DCHECK(task_in_progress_);
1437 if (!file_info.is_directory) {
1438 return HandleDeviceFileError(error_callback,
1439 dir_id,
1440 base::File::FILE_ERROR_NOT_A_DIRECTORY);
1441 }
1442
1443 base::Closure task_closure = base::Bind(
1444 &ReadDirectoryOnUIThread, storage_name_, read_only_, dir_id,
1445 0 /* max_size */,
1446 base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadDirectory,
1447 weak_ptr_factory_.GetWeakPtr(), dir_id, success_callback),
1448 base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
1449 weak_ptr_factory_.GetWeakPtr(), error_callback, dir_id));
1450 content::BrowserThread::PostTask(content::BrowserThread::UI,
1451 FROM_HERE,
1452 task_closure);
1453 }
1454
1455 void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToCreateSnapshotFile(
1456 std::unique_ptr<SnapshotRequestInfo> snapshot_request_info,
1457 const base::File::Info& file_info) {
1458 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1459 DCHECK(!current_snapshot_request_info_.get());
1460 DCHECK(snapshot_request_info.get());
1461 DCHECK(task_in_progress_);
1462 base::File::Error error = base::File::FILE_OK;
1463 if (file_info.is_directory)
1464 error = base::File::FILE_ERROR_NOT_A_FILE;
1465 else if (file_info.size < 0 ||
1466 file_info.size > std::numeric_limits<uint32_t>::max())
1467 error = base::File::FILE_ERROR_FAILED;
1468
1469 if (error != base::File::FILE_OK)
1470 return HandleDeviceFileError(snapshot_request_info->error_callback,
1471 snapshot_request_info->file_id,
1472 error);
1473
1474 base::File::Info snapshot_file_info(file_info);
1475 // Modify the last modified time to null. This prevents the time stamp
1476 // verfication in LocalFileStreamReader.
1477 snapshot_file_info.last_modified = base::Time();
1478
1479 current_snapshot_request_info_.reset(snapshot_request_info.release());
1480 if (file_info.size == 0) {
1481 // Empty snapshot file.
1482 return OnDidWriteDataIntoSnapshotFile(
1483 snapshot_file_info, current_snapshot_request_info_->snapshot_file_path);
1484 }
1485 WriteDataIntoSnapshotFile(snapshot_file_info);
1486 }
1487
1488 void MTPDeviceDelegateImplLinux::OnDidGetDestFileInfoToCopyFileFromLocal(
1489 const ErrorCallback& error_callback,
1490 const base::File::Info& file_info) {
1491 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1492
1493 if (file_info.is_directory)
1494 error_callback.Run(base::File::FILE_ERROR_INVALID_OPERATION);
1495 else
1496 error_callback.Run(base::File::FILE_ERROR_FAILED);
1497 }
1498
1499 void MTPDeviceDelegateImplLinux::OnGetDestFileInfoErrorToCopyFileFromLocal(
1500 const base::FilePath& source_file_path,
1501 const base::FilePath& device_file_path,
1502 const CopyFileFromLocalSuccessCallback& success_callback,
1503 const ErrorCallback& error_callback,
1504 const base::File::Error error) {
1505 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1506
1507 if (error != base::File::FILE_ERROR_NOT_FOUND) {
1508 error_callback.Run(error);
1509 return;
1510 }
1511
1512 content::BrowserThread::PostTaskAndReplyWithResult(
1513 content::BrowserThread::FILE, FROM_HERE,
1514 base::Bind(&OpenFileDescriptor, source_file_path.value().c_str(),
1515 O_RDONLY),
1516 base::Bind(&MTPDeviceDelegateImplLinux::OnDidOpenFDToCopyFileFromLocal,
1517 weak_ptr_factory_.GetWeakPtr(), device_file_path,
1518 success_callback, error_callback));
1519 }
1520
1521 void MTPDeviceDelegateImplLinux::OnDidCreateSingleDirectory(
1522 const base::FilePath& directory_path,
1523 const CreateDirectorySuccessCallback& success_callback) {
1524 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1525
1526 success_callback.Run();
1527 NotifyFileChange(directory_path.DirName(),
1528 storage::WatcherManager::ChangeType::CHANGED);
1529 PendingRequestDone();
1530 }
1531
1532 void MTPDeviceDelegateImplLinux::OnDidCreateParentDirectoryToCreateDirectory(
1533 const base::FilePath& created_directory,
1534 const std::vector<base::FilePath>& components,
1535 const bool exclusive,
1536 const CreateDirectorySuccessCallback& success_callback,
1537 const ErrorCallback& error_callback) {
1538 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1539
1540 // Calls ReadDirectoryInternal to fill the cache for created directory.
1541 // Calls ReadDirectoryInternal in this method to call it via
1542 // EnsureInitAndRunTask.
1543 const ReadDirectorySuccessCallback& success_callback_wrapper = base::Bind(
1544 &MTPDeviceDelegateImplLinux::OnDidReadDirectoryToCreateDirectory,
1545 weak_ptr_factory_.GetWeakPtr(), components, exclusive, success_callback,
1546 error_callback);
1547 const base::Closure closure =
1548 base::Bind(&MTPDeviceDelegateImplLinux::ReadDirectoryInternal,
1549 weak_ptr_factory_.GetWeakPtr(), created_directory.DirName(),
1550 success_callback_wrapper, error_callback);
1551 EnsureInitAndRunTask(PendingTaskInfo(
1552 base::FilePath(), content::BrowserThread::IO, FROM_HERE, closure));
1553 }
1554
1555 void MTPDeviceDelegateImplLinux::OnCreateParentDirectoryErrorToCreateDirectory(
1556 const ErrorCallback& callback,
1557 const base::File::Error error) {
1558 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1559
1560 callback.Run(base::File::FILE_ERROR_FAILED);
1561 }
1562
1563 void MTPDeviceDelegateImplLinux::OnDidReadDirectory(
1564 uint32_t dir_id,
1565 const ReadDirectorySuccessCallback& success_callback,
1566 const MTPDeviceTaskHelper::MTPEntries& mtp_entries,
1567 bool has_more) {
1568 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1569
1570 FileIdToMTPFileNodeMap::iterator it = file_id_to_node_map_.find(dir_id);
1571 DCHECK(it != file_id_to_node_map_.end());
1572 MTPFileNode* dir_node = it->second;
1573
1574 // Traverse the MTPFileNode tree to reconstuct the full path for |dir_id|.
1575 std::deque<std::string> dir_path_parts;
1576 MTPFileNode* parent_node = dir_node;
1577 while (parent_node->parent()) {
1578 dir_path_parts.push_front(parent_node->file_name());
1579 parent_node = parent_node->parent();
1580 }
1581 base::FilePath dir_path = device_path_;
1582 for (const auto& dir_path_part : dir_path_parts)
1583 dir_path = dir_path.Append(dir_path_part);
1584
1585 storage::AsyncFileUtil::EntryList file_list;
1586 for (const auto& mtp_entry : mtp_entries) {
1587 storage::DirectoryEntry entry;
1588 entry.name = mtp_entry.name;
1589 entry.is_directory = mtp_entry.file_info.is_directory;
1590 file_list.push_back(entry);
1591
1592 // Refresh the in memory tree.
1593 dir_node->EnsureChildExists(entry.name, mtp_entry.file_id);
1594 child_nodes_seen_.insert(entry.name);
1595
1596 // Add to |file_info_cache_|.
1597 file_info_cache_[dir_path.Append(entry.name)] = mtp_entry;
1598 }
1599
1600 success_callback.Run(file_list, has_more);
1601 if (has_more)
1602 return; // Wait to be called again.
1603
1604 // Last call, finish book keeping and continue with the next request.
1605 dir_node->ClearNonexistentChildren(child_nodes_seen_);
1606 child_nodes_seen_.clear();
1607 file_info_cache_.clear();
1608
1609 PendingRequestDone();
1610 }
1611
1612 void MTPDeviceDelegateImplLinux::OnDidWriteDataIntoSnapshotFile(
1613 const base::File::Info& file_info,
1614 const base::FilePath& snapshot_file_path) {
1615 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1616 DCHECK(current_snapshot_request_info_.get());
1617 current_snapshot_request_info_->success_callback.Run(
1618 file_info, snapshot_file_path);
1619 current_snapshot_request_info_.reset();
1620 PendingRequestDone();
1621 }
1622
1623 void MTPDeviceDelegateImplLinux::OnWriteDataIntoSnapshotFileError(
1624 base::File::Error error) {
1625 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1626 DCHECK(current_snapshot_request_info_.get());
1627 current_snapshot_request_info_->error_callback.Run(error);
1628 current_snapshot_request_info_.reset();
1629 PendingRequestDone();
1630 }
1631
1632 void MTPDeviceDelegateImplLinux::OnDidReadBytes(
1633 const ReadBytesSuccessCallback& success_callback,
1634 const base::File::Info& file_info, int bytes_read) {
1635 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1636 success_callback.Run(file_info, bytes_read);
1637 PendingRequestDone();
1638 }
1639
1640 void MTPDeviceDelegateImplLinux::OnDidFillFileCache(
1641 const base::FilePath& path,
1642 const storage::AsyncFileUtil::EntryList& /* entries */,
1643 bool has_more) {
1644 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1645 DCHECK(path.IsParent(pending_tasks_.front().path));
1646 if (has_more)
1647 return; // Wait until all entries have been read.
1648 pending_tasks_.front().cached_path = path;
1649 }
1650
1651 void MTPDeviceDelegateImplLinux::OnFillFileCacheFailed(
1652 base::File::Error /* error */) {
1653 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1654 // When filling the cache fails for the task at the front of the queue, clear
1655 // the path of the task so it will not try to do any more caching. Instead,
1656 // the task will just run and fail the CachedPathToId() lookup.
1657 pending_tasks_.front().path.clear();
1658 }
1659
1660 void MTPDeviceDelegateImplLinux::OnDidCreateTemporaryFileToCopyFileLocal(
1661 const base::FilePath& source_file_path,
1662 const base::FilePath& device_file_path,
1663 const CopyFileProgressCallback& progress_callback,
1664 const CopyFileLocalSuccessCallback& success_callback,
1665 const ErrorCallback& error_callback,
1666 const base::FilePath& temporary_file_path) {
1667 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1668
1669 if (temporary_file_path.empty()) {
1670 error_callback.Run(base::File::FILE_ERROR_FAILED);
1671 return;
1672 }
1673
1674 CreateSnapshotFile(
1675 source_file_path, temporary_file_path,
1676 base::Bind(
1677 &MTPDeviceDelegateImplLinux::OnDidCreateSnapshotFileOfCopyFileLocal,
1678 weak_ptr_factory_.GetWeakPtr(), device_file_path, progress_callback,
1679 success_callback, error_callback),
1680 base::Bind(&MTPDeviceDelegateImplLinux::HandleCopyFileLocalError,
1681 weak_ptr_factory_.GetWeakPtr(), error_callback,
1682 temporary_file_path));
1683 }
1684
1685 void MTPDeviceDelegateImplLinux::OnDidCreateSnapshotFileOfCopyFileLocal(
1686 const base::FilePath& device_file_path,
1687 const CopyFileProgressCallback& progress_callback,
1688 const CopyFileLocalSuccessCallback& success_callback,
1689 const ErrorCallback& error_callback,
1690 const base::File::Info& file_info,
1691 const base::FilePath& temporary_file_path) {
1692 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1693
1694 // Consider that half of copy is completed by creating a temporary file.
1695 progress_callback.Run(file_info.size / 2);
1696
1697 // TODO(yawano): Avoid to call external method from internal code.
1698 CopyFileFromLocal(
1699 temporary_file_path, device_file_path,
1700 base::Bind(
1701 &MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocalOfCopyFileLocal,
1702 weak_ptr_factory_.GetWeakPtr(), success_callback,
1703 temporary_file_path),
1704 base::Bind(&MTPDeviceDelegateImplLinux::HandleCopyFileLocalError,
1705 weak_ptr_factory_.GetWeakPtr(), error_callback,
1706 temporary_file_path));
1707 }
1708
1709 void MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocalOfCopyFileLocal(
1710 const CopyFileFromLocalSuccessCallback success_callback,
1711 const base::FilePath& temporary_file_path) {
1712 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1713
1714 DeleteTemporaryFile(temporary_file_path);
1715 success_callback.Run();
1716 }
1717
1718 void MTPDeviceDelegateImplLinux::OnDidMoveFileLocalWithRename(
1719 const MoveFileLocalSuccessCallback& success_callback,
1720 const base::FilePath& source_file_path,
1721 const uint32_t file_id) {
1722 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1723
1724 EvictCachedPathToId(file_id);
1725 success_callback.Run();
1726 NotifyFileChange(source_file_path,
1727 storage::WatcherManager::ChangeType::DELETED);
1728 NotifyFileChange(source_file_path.DirName(),
1729 storage::WatcherManager::ChangeType::CHANGED);
1730 PendingRequestDone();
1731 }
1732
1733 void MTPDeviceDelegateImplLinux::OnDidCopyFileFromLocal(
1734 const CopyFileFromLocalSuccessCallback& success_callback,
1735 const base::FilePath& file_path,
1736 const int source_file_descriptor) {
1737 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1738
1739 const base::Closure closure = base::Bind(&CloseFileDescriptor,
1740 source_file_descriptor);
1741
1742 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1743 closure);
1744
1745 success_callback.Run();
1746 NotifyFileChange(file_path.DirName(),
1747 storage::WatcherManager::ChangeType::CHANGED);
1748 PendingRequestDone();
1749 }
1750
1751 void MTPDeviceDelegateImplLinux::HandleCopyFileLocalError(
1752 const ErrorCallback& error_callback,
1753 const base::FilePath& temporary_file_path,
1754 const base::File::Error error) {
1755 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1756
1757 DeleteTemporaryFile(temporary_file_path);
1758 error_callback.Run(error);
1759 }
1760
1761 void MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError(
1762 const ErrorCallback& error_callback,
1763 const int source_file_descriptor,
1764 base::File::Error error) {
1765 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1766
1767 const base::Closure closure = base::Bind(&CloseFileDescriptor,
1768 source_file_descriptor);
1769
1770 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1771 closure);
1772
1773 error_callback.Run(error);
1774 PendingRequestDone();
1775 }
1776
1777 void MTPDeviceDelegateImplLinux::OnDidDeleteObject(
1778 const base::FilePath& object_path,
1779 const uint32_t object_id,
1780 const DeleteObjectSuccessCallback success_callback) {
1781 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1782
1783 EvictCachedPathToId(object_id);
1784 success_callback.Run();
1785 NotifyFileChange(object_path, storage::WatcherManager::ChangeType::DELETED);
1786 NotifyFileChange(object_path.DirName(),
1787 storage::WatcherManager::ChangeType::CHANGED);
1788 PendingRequestDone();
1789 }
1790
1791 void MTPDeviceDelegateImplLinux::HandleDeleteFileOrDirectoryError(
1792 const ErrorCallback& error_callback,
1793 base::File::Error error) {
1794 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1795
1796 error_callback.Run(error);
1797 PendingRequestDone();
1798 }
1799
1800 void MTPDeviceDelegateImplLinux::HandleDeviceFileError(
1801 const ErrorCallback& error_callback,
1802 uint32_t file_id,
1803 base::File::Error error) {
1804 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1805
1806 EvictCachedPathToId(file_id);
1807 error_callback.Run(error);
1808 PendingRequestDone();
1809 }
1810
1811 base::FilePath MTPDeviceDelegateImplLinux::NextUncachedPathComponent(
1812 const base::FilePath& path,
1813 const base::FilePath& cached_path) const {
1814 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1815 DCHECK(cached_path.empty() || cached_path.IsParent(path));
1816
1817 base::FilePath uncached_path;
1818 std::string device_relpath = GetDeviceRelativePath(device_path_, path);
1819 if (!device_relpath.empty() && device_relpath != kRootPath) {
1820 uncached_path = device_path_;
1821 std::vector<std::string> device_relpath_components = base::SplitString(
1822 device_relpath, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
1823 DCHECK(!device_relpath_components.empty());
1824 bool all_components_cached = true;
1825 const MTPFileNode* current_node = root_node_.get();
1826 for (size_t i = 0; i < device_relpath_components.size(); ++i) {
1827 current_node = current_node->GetChild(device_relpath_components[i]);
1828 if (!current_node) {
1829 // With a cache miss, check if it is a genuine failure. If so, pretend
1830 // the entire |path| is cached, so there is no further attempt to do
1831 // more caching. The actual operation will then fail.
1832 all_components_cached =
1833 !cached_path.empty() && (uncached_path == cached_path);
1834 break;
1835 }
1836 uncached_path = uncached_path.Append(device_relpath_components[i]);
1837 }
1838 if (all_components_cached)
1839 uncached_path.clear();
1840 }
1841 return uncached_path;
1842 }
1843
1844 void MTPDeviceDelegateImplLinux::FillFileCache(
1845 const base::FilePath& uncached_path) {
1846 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1847 DCHECK(task_in_progress_);
1848
1849 ReadDirectorySuccessCallback success_callback =
1850 base::Bind(&MTPDeviceDelegateImplLinux::OnDidFillFileCache,
1851 weak_ptr_factory_.GetWeakPtr(),
1852 uncached_path);
1853 ErrorCallback error_callback =
1854 base::Bind(&MTPDeviceDelegateImplLinux::OnFillFileCacheFailed,
1855 weak_ptr_factory_.GetWeakPtr());
1856 ReadDirectoryInternal(uncached_path, success_callback, error_callback);
1857 }
1858
1859 bool MTPDeviceDelegateImplLinux::CachedPathToId(const base::FilePath& path,
1860 uint32_t* id) const {
1861 DCHECK(id);
1862
1863 std::string device_relpath = GetDeviceRelativePath(device_path_, path);
1864 if (device_relpath.empty())
1865 return false;
1866 std::vector<std::string> device_relpath_components;
1867 if (device_relpath != kRootPath) {
1868 device_relpath_components = base::SplitString(
1869 device_relpath, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
1870 }
1871 const MTPFileNode* current_node = root_node_.get();
1872 for (size_t i = 0; i < device_relpath_components.size(); ++i) {
1873 current_node = current_node->GetChild(device_relpath_components[i]);
1874 if (!current_node)
1875 return false;
1876 }
1877 *id = current_node->file_id();
1878 return true;
1879 }
1880
1881 void MTPDeviceDelegateImplLinux::EvictCachedPathToId(const uint32_t id) {
1882 FileIdToMTPFileNodeMap::iterator it = file_id_to_node_map_.find(id);
1883 if (it != file_id_to_node_map_.end()) {
1884 DCHECK(!it->second->HasChildren());
1885 MTPFileNode* parent = it->second->parent();
1886 if (parent) {
1887 const bool ret = parent->DeleteChild(id);
1888 DCHECK(ret);
1889 }
1890 }
1891 }
1892
1893 void CreateMTPDeviceAsyncDelegate(
1894 const std::string& device_location,
1895 const bool read_only,
1896 const CreateMTPDeviceAsyncDelegateCallback& callback) {
1897 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1898 callback.Run(new MTPDeviceDelegateImplLinux(device_location, read_only));
1899 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698