| OLD | NEW |
| (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 } | |
| OLD | NEW |