Index: chrome/browser/media_gallery/mtp_device_delegate_impl_linux.cc |
diff --git a/chrome/browser/media_gallery/mtp_device_delegate_impl_linux.cc b/chrome/browser/media_gallery/mtp_device_delegate_impl_linux.cc |
deleted file mode 100644 |
index 6977d8d5739bf99e41657478de1964753a07541b..0000000000000000000000000000000000000000 |
--- a/chrome/browser/media_gallery/mtp_device_delegate_impl_linux.cc |
+++ /dev/null |
@@ -1,961 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/media_gallery/mtp_device_delegate_impl_linux.h" |
- |
-#include <fcntl.h> |
-#include <sys/stat.h> |
-#include <sys/types.h> |
- |
-#include "base/bind.h" |
-#include "base/file_path.h" |
-#include "base/file_util.h" |
-#include "base/sequenced_task_runner.h" |
-#include "base/sequenced_task_runner_helpers.h" |
-#include "base/string_util.h" |
-#include "base/synchronization/cancellation_flag.h" |
-#include "base/threading/sequenced_worker_pool.h" |
-#include "chrome/browser/media_transfer_protocol/media_transfer_protocol_manager.h" |
-#include "chrome/browser/media_transfer_protocol/mtp_file_entry.pb.h" |
-#include "content/public/browser/browser_thread.h" |
-#include "third_party/cros_system_api/dbus/service_constants.h" |
- |
-using base::Bind; |
-using base::PlatformFileError; |
-using base::PlatformFileInfo; |
-using base::SequencedTaskRunner; |
-using base::Time; |
-using content::BrowserThread; |
-using fileapi::FileSystemFileUtil; |
- |
-namespace chrome { |
- |
-namespace { |
- |
-using base::DeleteHelper; |
-using base::RefCountedThreadSafe; |
-using base::WaitableEvent; |
- |
-// Helper struct to delete worker objects on |media_task_runner_| thread. |
-template <typename WORKER> struct WorkerDeleter { |
- static void Destruct(const WORKER* worker) { |
- if (!worker->media_task_runner()->RunsTasksOnCurrentThread()) { |
- worker->media_task_runner()->DeleteSoon(FROM_HERE, worker); |
- return; |
- } |
- delete worker; |
- } |
-}; |
- |
-typedef struct WorkerDeleter<class GetFileInfoWorker> GetFileInfoWorkerDeleter; |
-typedef struct WorkerDeleter<class OpenStorageWorker> OpenStorageWorkerDeleter; |
-typedef struct WorkerDeleter<class ReadDirectoryWorker> |
- ReadDirectoryWorkerDeleter; |
-typedef struct WorkerDeleter<class ReadFileWorker> ReadFileWorkerDeleter; |
- |
-// File path separator constant. |
-const char kRootPath[] = "/"; |
- |
-// Returns MediaTransferProtocolManager instance on success or NULL on failure. |
-MediaTransferProtocolManager* GetMediaTransferProtocolManager() { |
- MediaTransferProtocolManager* mtp_device_mgr = |
- MediaTransferProtocolManager::GetInstance(); |
- DCHECK(mtp_device_mgr); |
- return mtp_device_mgr; |
-} |
- |
-// Does nothing. |
-// This method is used to handle the results of |
-// MediaTransferProtocolManager::CloseStorage method call. |
-void DoNothing(bool error) { |
-} |
- |
-// Closes the device storage on the UI thread. |
-void CloseStorageOnUIThread(const std::string& device_handle) { |
- DCHECK(!device_handle.empty()); |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- GetMediaTransferProtocolManager()->CloseStorage(device_handle, |
- Bind(&DoNothing)); |
-} |
- |
-// Returns the device relative file path given |file_path|. |
-// E.g.: If the |file_path| is "/usb:2,2:12345/DCIM" and |registered_dev_path| |
-// is "/usb:2,2:12345", this function returns the device relative path which is |
-// "/DCIM". |
-std::string GetDeviceRelativePath(const std::string& registered_dev_path, |
- const std::string& file_path) { |
- DCHECK(!registered_dev_path.empty()); |
- DCHECK(!file_path.empty()); |
- |
- std::string actual_file_path; |
- if (registered_dev_path == file_path) { |
- actual_file_path = kRootPath; |
- } else { |
- actual_file_path = file_path; |
- ReplaceFirstSubstringAfterOffset(&actual_file_path, 0, |
- registered_dev_path.c_str(), ""); |
- } |
- DCHECK(!actual_file_path.empty()); |
- return actual_file_path; |
-} |
- |
-// Worker class to open a MTP device for communication. This class is |
-// instantiated and destructed on |media_task_runner_|. In order to post a |
-// request on Dbus thread, the caller should run on UI thread. Therefore, this |
-// class posts the open device request on UI thread and receives the response |
-// on UI thread. |
-class OpenStorageWorker |
- : public RefCountedThreadSafe<OpenStorageWorker, OpenStorageWorkerDeleter> { |
- public: |
- // Constructed on |media_task_runner_| thread. |
- OpenStorageWorker(const std::string& name, SequencedTaskRunner* task_runner, |
- WaitableEvent* task_completed_event, |
- WaitableEvent* shutdown_event) |
- : storage_name_(name), |
- media_task_runner_(task_runner), |
- on_task_completed_event_(task_completed_event), |
- on_shutdown_event_(shutdown_event) { |
- DCHECK(on_task_completed_event_); |
- DCHECK(on_shutdown_event_); |
- } |
- |
- // This function is invoked on |media_task_runner_| to post the task on UI |
- // thread. This blocks the |media_task_runner_| until the task is complete. |
- void Run() { |
- if (on_shutdown_event_->IsSignaled()) { |
- // Process is in shutdown mode. |
- // Do not post any task on |media_task_runner_|. |
- return; |
- } |
- |
- DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- Bind(&OpenStorageWorker::DoWorkOnUIThread, this)); |
- on_task_completed_event_->Wait(); |
- |
- if (on_shutdown_event_->IsSignaled()) |
- cancel_tasks_flag_.Set(); |
- } |
- |
- // Returns a device handle string if the OpenStorage() request was |
- // successfully completed or an empty string otherwise. |
- const std::string& device_handle() const { return device_handle_; } |
- |
- // Returns the |media_task_runner_| associated with this worker object. |
- // This function is exposed for WorkerDeleter struct to access the |
- // |media_task_runner_|. |
- SequencedTaskRunner* media_task_runner() const { |
- return media_task_runner_.get(); |
- } |
- |
- private: |
- friend struct WorkerDeleter<OpenStorageWorker>; |
- friend class DeleteHelper<OpenStorageWorker>; |
- friend class RefCountedThreadSafe<OpenStorageWorker, |
- OpenStorageWorkerDeleter>; |
- |
- // Destructed via OpenStorageWorkerDeleter struct. |
- virtual ~OpenStorageWorker() { |
- // This object must be destructed on |media_task_runner_|. |
- } |
- |
- // Dispatches a request to MediaTransferProtocolManager to open the MTP |
- // storage for communication. This is called on UI thread. |
- void DoWorkOnUIThread() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (cancel_tasks_flag_.IsSet()) |
- return; |
- |
- GetMediaTransferProtocolManager()->OpenStorage( |
- storage_name_, mtpd::kReadOnlyMode, |
- Bind(&OpenStorageWorker::OnDidWorkOnUIThread, this)); |
- } |
- |
- // Query callback for DoWorkOnUIThread(). |error| is set to true if the device |
- // did not open successfully. This function signals to unblock |
- // |media_task_runner_|. |
- void OnDidWorkOnUIThread(const std::string& device_handle, bool error) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (cancel_tasks_flag_.IsSet()) |
- return; |
- |
- if (!error) |
- device_handle_ = device_handle; |
- on_task_completed_event_->Signal(); |
- } |
- |
- // Stores the storage name to open the device. |
- const std::string storage_name_; |
- |
- // Stores a reference to |media_task_runner_| to destruct this object on the |
- // correct thread. |
- scoped_refptr<SequencedTaskRunner> media_task_runner_; |
- |
- // |media_task_runner_| can wait on this event until the required operation |
- // is complete. |
- // TODO(kmadhusu): Remove this WaitableEvent after modifying the |
- // DeviceMediaFileUtil functions as asynchronous functions. |
- WaitableEvent* on_task_completed_event_; |
- |
- // Stores a reference to waitable event associated with the shut down message. |
- WaitableEvent* on_shutdown_event_; |
- |
- // Stores the result of OpenStorage() request. |
- std::string device_handle_; |
- |
- // Set to ignore the request results. This will be set when |
- // MTPDeviceDelegateImplLinux object is about to be deleted. |
- // |on_task_completed_event_| and |on_shutdown_event_| should not be |
- // dereferenced when this is set. |
- base::CancellationFlag cancel_tasks_flag_; |
- |
- DISALLOW_COPY_AND_ASSIGN(OpenStorageWorker); |
-}; |
- |
-// Worker class to get media device file information given a |path|. |
-class GetFileInfoWorker |
- : public RefCountedThreadSafe<GetFileInfoWorker, GetFileInfoWorkerDeleter> { |
- public: |
- // Constructed on |media_task_runner_| thread. |
- GetFileInfoWorker(const std::string& handle, |
- const std::string& path, |
- SequencedTaskRunner* task_runner, |
- WaitableEvent* task_completed_event, |
- WaitableEvent* shutdown_event) |
- : device_handle_(handle), |
- path_(path), |
- media_task_runner_(task_runner), |
- error_(base::PLATFORM_FILE_OK), |
- on_task_completed_event_(task_completed_event), |
- on_shutdown_event_(shutdown_event) { |
- DCHECK(on_task_completed_event_); |
- DCHECK(on_shutdown_event_); |
- } |
- |
- // This function is invoked on |media_task_runner_| to post the task on UI |
- // thread. This blocks the |media_task_runner_| until the task is complete. |
- void Run() { |
- if (on_shutdown_event_->IsSignaled()) { |
- // Process is in shutdown mode. |
- // Do not post any task on |media_task_runner_|. |
- return; |
- } |
- |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- Bind(&GetFileInfoWorker::DoWorkOnUIThread, this)); |
- on_task_completed_event_->Wait(); |
- |
- if (on_shutdown_event_->IsSignaled()) |
- cancel_tasks_flag_.Set(); |
- } |
- |
- // Returns GetFileInfo() result and fills in |file_info| with requested file |
- // entry details. |
- PlatformFileError get_file_info(PlatformFileInfo* file_info) const { |
- if (file_info) |
- *file_info = file_entry_info_; |
- return error_; |
- } |
- |
- // Returns the |media_task_runner_| associated with this worker object. |
- // This function is exposed for WorkerDeleter struct to access the |
- // |media_task_runner_|. |
- SequencedTaskRunner* media_task_runner() const { |
- return media_task_runner_.get(); |
- } |
- |
- private: |
- friend struct WorkerDeleter<GetFileInfoWorker>; |
- friend class DeleteHelper<GetFileInfoWorker>; |
- friend class RefCountedThreadSafe<GetFileInfoWorker, |
- GetFileInfoWorkerDeleter>; |
- |
- // Destructed via GetFileInfoWorkerDeleter. |
- virtual ~GetFileInfoWorker() { |
- // This object must be destructed on |media_task_runner_|. |
- } |
- |
- // Dispatches a request to MediaTransferProtocolManager to get file |
- // information. |
- void DoWorkOnUIThread() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (cancel_tasks_flag_.IsSet()) { |
- error_ = base::PLATFORM_FILE_ERROR_FAILED; |
- return; |
- } |
- |
- GetMediaTransferProtocolManager()->GetFileInfoByPath( |
- device_handle_, path_, |
- Bind(&GetFileInfoWorker::OnDidWorkOnUIThread, this)); |
- } |
- |
- // Query callback for DoWorkOnUIThread(). On success, |file_entry| has media |
- // file information. On failure, |error| is set to true. This function signals |
- // to unblock |media_task_runner_|. |
- void OnDidWorkOnUIThread(const MtpFileEntry& file_entry, bool error) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (cancel_tasks_flag_.IsSet()) { |
- error_ = base::PLATFORM_FILE_ERROR_FAILED; |
- return; |
- } |
- |
- if (error) { |
- error_ = base::PLATFORM_FILE_ERROR_NOT_FOUND; |
- } else { |
- file_entry_info_.size = file_entry.file_size(); |
- file_entry_info_.is_directory = |
- file_entry.file_type() == MtpFileEntry::FILE_TYPE_FOLDER; |
- file_entry_info_.is_symbolic_link = false; |
- file_entry_info_.last_modified = |
- base::Time::FromTimeT(file_entry.modification_time()); |
- file_entry_info_.last_accessed = |
- base::Time::FromTimeT(file_entry.modification_time()); |
- file_entry_info_.creation_time = base::Time(); |
- } |
- on_task_completed_event_->Signal(); |
- } |
- |
- // Stores the device handle to query the device. |
- const std::string device_handle_; |
- |
- // Stores the requested media device file path. |
- const std::string path_; |
- |
- // Stores a reference to |media_task_runner_| to destruct this object on the |
- // correct thread. |
- scoped_refptr<SequencedTaskRunner> media_task_runner_; |
- |
- // Stores the result of GetFileInfo(). |
- PlatformFileError error_; |
- |
- // Stores the media file entry information. |
- PlatformFileInfo file_entry_info_; |
- |
- // |media_task_runner_| can wait on this event until the required operation |
- // is complete. |
- // TODO(kmadhusu): Remove this WaitableEvent after modifying the |
- // DeviceMediaFileUtil functions as asynchronous functions. |
- WaitableEvent* on_task_completed_event_; |
- |
- // Stores a reference to waitable event associated with the shut down message. |
- WaitableEvent* on_shutdown_event_; |
- |
- // Set to ignore the request results. This will be set when |
- // MTPDeviceDelegateImplLinux object is about to be deleted. |
- // |on_task_completed_event_| and |on_shutdown_event_| should not be |
- // dereferenced when this is set. |
- base::CancellationFlag cancel_tasks_flag_; |
- |
- DISALLOW_COPY_AND_ASSIGN(GetFileInfoWorker); |
-}; |
- |
-// Worker class to read media device file data given a file |path|. |
-class ReadFileWorker |
- : public RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter> { |
- public: |
- // Constructed on |media_task_runner_| thread. |
- ReadFileWorker(const std::string& handle, |
- const std::string& src_path, |
- uint32 total_size, |
- const FilePath& dest_path, |
- SequencedTaskRunner* task_runner, |
- WaitableEvent* task_completed_event, |
- WaitableEvent* shutdown_event) |
- : device_handle_(handle), |
- src_path_(src_path), |
- total_bytes_(total_size), |
- dest_path_(dest_path), |
- bytes_read_(0), |
- error_occurred_(false), |
- media_task_runner_(task_runner), |
- on_task_completed_event_(task_completed_event), |
- on_shutdown_event_(shutdown_event) { |
- DCHECK(on_task_completed_event_); |
- DCHECK(on_shutdown_event_); |
- } |
- |
- // This function is invoked on |media_task_runner_| to post the task on UI |
- // thread. This blocks the |media_task_runner_| until the task is complete. |
- void Run() { |
- if (on_shutdown_event_->IsSignaled()) { |
- // Process is in shutdown mode. |
- // Do not post any task on |media_task_runner_|. |
- return; |
- } |
- |
- int dest_fd = open(dest_path_.value().c_str(), O_WRONLY); |
- if (dest_fd < 0) |
- return; |
- file_util::ScopedFD dest_fd_scoper(&dest_fd); |
- |
- while (bytes_read_ < total_bytes_) { |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- Bind(&ReadFileWorker::DoWorkOnUIThread, this)); |
- on_task_completed_event_->Wait(); |
- if (error_occurred_) |
- break; |
- if (on_shutdown_event_->IsSignaled()) { |
- cancel_tasks_flag_.Set(); |
- break; |
- } |
- |
- int bytes_written = |
- file_util::WriteFileDescriptor(dest_fd, data_.data(), data_.size()); |
- if (static_cast<int>(data_.size()) != bytes_written) |
- break; |
- |
- bytes_read_ += data_.size(); |
- } |
- } |
- |
- bool Succeeded() const { |
- return !error_occurred_ && (bytes_read_ == total_bytes_); |
- } |
- |
- // Returns the |media_task_runner_| associated with this worker object. |
- // This function is exposed for WorkerDeleter struct to access the |
- // |media_task_runner_|. |
- SequencedTaskRunner* media_task_runner() const { |
- return media_task_runner_.get(); |
- } |
- |
- private: |
- friend struct WorkerDeleter<ReadFileWorker>; |
- friend class DeleteHelper<ReadFileWorker>; |
- friend class RefCountedThreadSafe<ReadFileWorker, ReadFileWorkerDeleter>; |
- |
- // Destructed via ReadFileWorkerDeleter. |
- virtual ~ReadFileWorker() { |
- // This object must be destructed on |media_task_runner_|. |
- } |
- |
- // Dispatches a request to MediaTransferProtocolManager to get the media file |
- // contents. |
- void DoWorkOnUIThread() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (cancel_tasks_flag_.IsSet()) |
- return; |
- |
- GetMediaTransferProtocolManager()->ReadFileChunkByPath( |
- device_handle_, src_path_, bytes_read_, BytesToRead(), |
- Bind(&ReadFileWorker::OnDidWorkOnUIThread, this)); |
- } |
- |
- // Query callback for DoWorkOnUIThread(). On success, |data| has the media |
- // file contents. On failure, |error| is set to true. This function signals |
- // to unblock |media_task_runner_|. |
- void OnDidWorkOnUIThread(const std::string& data, bool error) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (cancel_tasks_flag_.IsSet()) |
- return; |
- |
- error_occurred_ = error || (data.size() != BytesToRead()); |
- if (!error_occurred_) |
- data_ = data; |
- on_task_completed_event_->Signal(); |
- } |
- |
- uint32 BytesToRead() const { |
- // Read data in 1 MB chunks. |
- static const uint32 kReadChunkSize = 1024 * 1024; |
- return std::min(kReadChunkSize, total_bytes_ - bytes_read_); |
- } |
- |
- // The device unique identifier to query the device. |
- const std::string device_handle_; |
- |
- // The media device file path. |
- const std::string src_path_; |
- |
- // Number of bytes to read. |
- const uint32 total_bytes_; |
- |
- // Where to write the data read from the device. |
- const FilePath dest_path_; |
- |
- /***************************************************************************** |
- * The variables below are accessed on both |media_task_runner_| and the UI |
- * thread. However, there's no concurrent access because the UI thread is in a |
- * blocked state when access occurs on |media_task_runner_|. |
- */ |
- |
- // Number of bytes read from the device. |
- uint32 bytes_read_; |
- |
- // Temporary data storage. |
- std::string data_; |
- |
- // Whether an error occurred during file transfer. |
- bool error_occurred_; |
- |
- /****************************************************************************/ |
- |
- // A reference to |media_task_runner_| to destruct this object on the correct |
- // thread. |
- scoped_refptr<SequencedTaskRunner> media_task_runner_; |
- |
- // |media_task_runner_| can wait on this event until the required operation |
- // is complete. |
- // TODO(kmadhusu): Remove this WaitableEvent after modifying the |
- // DeviceMediaFileUtil functions as asynchronous functions. |
- WaitableEvent* on_task_completed_event_; |
- |
- // Stores a reference to waitable event associated with the shut down message. |
- WaitableEvent* on_shutdown_event_; |
- |
- // Set to ignore the request results. This will be set when |
- // MTPDeviceDelegateImplLinux object is about to be deleted. |
- // |on_task_completed_event_| and |on_shutdown_event_| should not be |
- // dereferenced when this is set. |
- base::CancellationFlag cancel_tasks_flag_; |
- |
- DISALLOW_COPY_AND_ASSIGN(ReadFileWorker); |
-}; |
- |
-// Worker class to read directory contents. Device is already opened for |
-// communication. |
-class ReadDirectoryWorker |
- : public RefCountedThreadSafe<ReadDirectoryWorker, |
- ReadDirectoryWorkerDeleter> { |
- public: |
- // Construct a worker object given the directory |path|. This object is |
- // constructed on |media_task_runner_| thread. |
- ReadDirectoryWorker(const std::string& handle, |
- const std::string& path, |
- SequencedTaskRunner* task_runner, |
- WaitableEvent* task_completed_event, |
- WaitableEvent* shutdown_event) |
- : device_handle_(handle), |
- dir_path_(path), |
- dir_entry_id_(0), |
- media_task_runner_(task_runner), |
- on_task_completed_event_(task_completed_event), |
- on_shutdown_event_(shutdown_event) { |
- DCHECK(!dir_path_.empty()); |
- DCHECK(on_task_completed_event_); |
- DCHECK(on_shutdown_event_); |
- } |
- |
- // Construct a worker object given the directory |entry_id|. This object is |
- // constructed on |media_task_runner_| thread. |
- ReadDirectoryWorker(const std::string& storage_name, |
- const uint32_t entry_id, |
- SequencedTaskRunner* task_runner, |
- WaitableEvent* task_completed_event, |
- WaitableEvent* shutdown_event) |
- : device_handle_(storage_name), |
- dir_entry_id_(entry_id), |
- media_task_runner_(task_runner), |
- on_task_completed_event_(task_completed_event), |
- on_shutdown_event_(shutdown_event) { |
- DCHECK(on_task_completed_event_); |
- DCHECK(on_shutdown_event_); |
- } |
- |
- // This function is invoked on |media_task_runner_| to post the task on UI |
- // thread. This blocks the |media_task_runner_| until the task is complete. |
- void Run() { |
- if (on_shutdown_event_->IsSignaled()) { |
- // Process is in shutdown mode. |
- // Do not post any task on |media_task_runner_|. |
- return; |
- } |
- |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- Bind(&ReadDirectoryWorker::DoWorkOnUIThread, this)); |
- on_task_completed_event_->Wait(); |
- if (on_shutdown_event_->IsSignaled()) |
- cancel_tasks_flag_.Set(); |
- } |
- |
- // Returns the directory entries for the given directory path. |
- const std::vector<MtpFileEntry>& get_file_entries() const { |
- return file_entries_; |
- } |
- |
- // Returns the |media_task_runner_| associated with this worker object. |
- // This function is exposed for WorkerDeleter struct to access the |
- // |media_task_runner_|. |
- SequencedTaskRunner* media_task_runner() const { |
- return media_task_runner_.get(); |
- } |
- |
- private: |
- friend struct WorkerDeleter<ReadDirectoryWorker>; |
- friend class DeleteHelper<ReadDirectoryWorker>; |
- friend class RefCountedThreadSafe<ReadDirectoryWorker, |
- ReadDirectoryWorkerDeleter>; |
- |
- // Destructed via ReadDirectoryWorkerDeleter. |
- virtual ~ReadDirectoryWorker() { |
- // This object must be destructed on |media_task_runner_|. |
- } |
- |
- // Dispatches a request to MediaTransferProtocolManager to read the directory |
- // entries. This is called on UI thread. |
- void DoWorkOnUIThread() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (cancel_tasks_flag_.IsSet()) |
- return; |
- |
- if (!dir_path_.empty()) { |
- GetMediaTransferProtocolManager()->ReadDirectoryByPath( |
- device_handle_, dir_path_, |
- Bind(&ReadDirectoryWorker::OnDidWorkOnUIThread, this)); |
- } else { |
- GetMediaTransferProtocolManager()->ReadDirectoryById( |
- device_handle_, dir_entry_id_, |
- Bind(&ReadDirectoryWorker::OnDidWorkOnUIThread, this)); |
- } |
- } |
- |
- // Query callback for DoWorkOnUIThread(). On success, |file_entries| has the |
- // directory file entries. |error| is true if there was an error. This |
- // function signals to unblock |media_task_runner_|. |
- void OnDidWorkOnUIThread(const std::vector<MtpFileEntry>& file_entries, |
- bool error) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (cancel_tasks_flag_.IsSet()) |
- return; |
- |
- if (!error) |
- file_entries_ = file_entries; |
- on_task_completed_event_->Signal(); |
- } |
- |
- // Stores the device handle to communicate with storage device. |
- const std::string device_handle_; |
- |
- // Stores the directory path whose contents needs to be listed. |
- const std::string dir_path_; |
- |
- // Stores the directory entry id whose contents needs to be listed. |
- const uint32_t dir_entry_id_; |
- |
- // Stores a reference to |media_task_runner_| to destruct this object on the |
- // correct thread. |
- scoped_refptr<SequencedTaskRunner> media_task_runner_; |
- |
- // |media_task_runner_| can wait on this event until the required operation |
- // is complete. |
- // TODO(kmadhusu): Remove this WaitableEvent after modifying the |
- // DeviceMediaFileUtil functions as asynchronous functions. |
- WaitableEvent* on_task_completed_event_; |
- |
- // Stores a reference to waitable event associated with the shut down message. |
- WaitableEvent* on_shutdown_event_; |
- |
- // Stores the result of read directory request. |
- std::vector<MtpFileEntry> file_entries_; |
- |
- // Set to ignore the request results. This will be set when |
- // MTPDeviceDelegateImplLinux object is about to be deleted. |
- // |on_task_completed_event_| and |on_shutdown_event_| should not be |
- // dereferenced when this is set. |
- base::CancellationFlag cancel_tasks_flag_; |
- |
- DISALLOW_COPY_AND_ASSIGN(ReadDirectoryWorker); |
-}; |
- |
-// Simply enumerate each files from a given file entry list. |
-// Used to enumerate top-level files of an media file system. |
-class MediaFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { |
- public: |
- explicit MediaFileEnumerator(const std::vector<MtpFileEntry>& entries) |
- : file_entries_(entries), |
- file_entry_iter_(file_entries_.begin()) { |
- } |
- |
- virtual ~MediaFileEnumerator() {} |
- |
- // AbstractFileEnumerator override. |
- // Returns the next file entry path on success and empty file path on |
- // failure. |
- virtual FilePath Next() OVERRIDE { |
- if (file_entry_iter_ == file_entries_.end()) |
- return FilePath(); |
- |
- current_file_info_ = *file_entry_iter_; |
- ++file_entry_iter_; |
- return FilePath(current_file_info_.file_name()); |
- } |
- |
- // AbstractFileEnumerator override. |
- // Returns the size of the current file entry. |
- virtual int64 Size() OVERRIDE { |
- return current_file_info_.file_size(); |
- } |
- |
- // AbstractFileEnumerator override. |
- // Returns true if the current file entry is a directory else false. |
- virtual bool IsDirectory() OVERRIDE { |
- return current_file_info_.file_type() == MtpFileEntry::FILE_TYPE_FOLDER; |
- } |
- |
- // AbstractFileEnumerator override. |
- // Returns the last modified time of the current file entry. |
- virtual base::Time LastModifiedTime() OVERRIDE { |
- return base::Time::FromTimeT(current_file_info_.modification_time()); |
- } |
- |
- private: |
- // List of directory file entries information. |
- const std::vector<MtpFileEntry> file_entries_; |
- |
- // Iterator to access the individual file entries. |
- std::vector<MtpFileEntry>::const_iterator file_entry_iter_; |
- |
- // Stores the current file information. |
- MtpFileEntry current_file_info_; |
- |
- DISALLOW_COPY_AND_ASSIGN(MediaFileEnumerator); |
-}; |
- |
-// Recursively enumerate each file entry from a given media file entry set. |
-class RecursiveMediaFileEnumerator |
- : public FileSystemFileUtil::AbstractFileEnumerator { |
- public: |
- RecursiveMediaFileEnumerator(const std::string& handle, |
- SequencedTaskRunner* task_runner, |
- const std::vector<MtpFileEntry>& entries, |
- WaitableEvent* task_completed_event, |
- WaitableEvent* shutdown_event) |
- : device_handle_(handle), |
- media_task_runner_(task_runner), |
- file_entries_(entries), |
- file_entry_iter_(file_entries_.begin()), |
- on_task_completed_event_(task_completed_event), |
- on_shutdown_event_(shutdown_event) { |
- DCHECK(on_task_completed_event_); |
- DCHECK(on_shutdown_event_); |
- current_enumerator_.reset(new MediaFileEnumerator(entries)); |
- } |
- |
- virtual ~RecursiveMediaFileEnumerator() {} |
- |
- // AbstractFileEnumerator override. |
- // Returns the next file entry path on success and empty file path on |
- // failure or when it reaches the end. |
- virtual FilePath Next() OVERRIDE { |
- if (on_shutdown_event_->IsSignaled()) { |
- // Process is in shut down mode. |
- return FilePath(); |
- } |
- |
- FilePath path = current_enumerator_->Next(); |
- if (!path.empty()) |
- return path; |
- |
- // We reached the end. |
- if (file_entry_iter_ == file_entries_.end()) |
- return FilePath(); |
- |
- // Enumerate subdirectories of the next media file entry. |
- MtpFileEntry next_file_entry = *file_entry_iter_; |
- ++file_entry_iter_; |
- |
- // Create a ReadDirectoryWorker object to enumerate sub directories. |
- scoped_refptr<ReadDirectoryWorker> worker(new ReadDirectoryWorker( |
- device_handle_, next_file_entry.item_id(), media_task_runner_, |
- on_task_completed_event_, on_shutdown_event_)); |
- worker->Run(); |
- if (!worker->get_file_entries().empty()) { |
- current_enumerator_.reset( |
- new MediaFileEnumerator(worker->get_file_entries())); |
- } else { |
- current_enumerator_.reset(new FileSystemFileUtil::EmptyFileEnumerator()); |
- } |
- return current_enumerator_->Next(); |
- } |
- |
- // AbstractFileEnumerator override. |
- // Returns the size of the current file entry. |
- virtual int64 Size() OVERRIDE { |
- return current_enumerator_->Size(); |
- } |
- |
- // AbstractFileEnumerator override. |
- // Returns true if the current media file entry is a folder type else false. |
- virtual bool IsDirectory() OVERRIDE { |
- return current_enumerator_->IsDirectory(); |
- } |
- |
- // AbstractFileEnumerator override. |
- // Returns the last modified time of the current file entry. |
- virtual base::Time LastModifiedTime() OVERRIDE { |
- return current_enumerator_->LastModifiedTime(); |
- } |
- |
- private: |
- // Stores the device handle that was used to open the device. |
- const std::string device_handle_; |
- |
- // Stores a reference to |media_task_runner_| to construct and destruct |
- // ReadDirectoryWorker object on the correct thread. |
- scoped_refptr<SequencedTaskRunner> media_task_runner_; |
- |
- // List of top-level directory file entries. |
- const std::vector<MtpFileEntry> file_entries_; |
- |
- // Iterator to access the individual file entries. |
- std::vector<MtpFileEntry>::const_iterator file_entry_iter_; |
- |
- // Enumerator to access current directory Id/path entries. |
- scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> current_enumerator_; |
- |
- // |media_task_runner_| can wait on this event until the requested operation |
- // is complete. |
- WaitableEvent* on_task_completed_event_; |
- |
- // Stores a reference to waitable event associated with the shut down message. |
- WaitableEvent* on_shutdown_event_; |
- |
- DISALLOW_COPY_AND_ASSIGN(RecursiveMediaFileEnumerator); |
-}; |
- |
-} // namespace |
- |
-MTPDeviceDelegateImplLinux::MTPDeviceDelegateImplLinux( |
- const std::string& device_location) |
- : device_path_(device_location), |
- on_task_completed_event_(false, false), |
- on_shutdown_event_(true, false) { |
- CHECK(!device_path_.empty()); |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool(); |
- base::SequencedWorkerPool::SequenceToken media_sequence_token = |
- pool->GetNamedSequenceToken("media-task-runner"); |
- media_task_runner_ = pool->GetSequencedTaskRunner(media_sequence_token); |
-} |
- |
-PlatformFileError MTPDeviceDelegateImplLinux::GetFileInfo( |
- const FilePath& file_path, |
- PlatformFileInfo* file_info) { |
- if (!LazyInit()) |
- return base::PLATFORM_FILE_ERROR_FAILED; |
- |
- scoped_refptr<GetFileInfoWorker> worker(new GetFileInfoWorker( |
- device_handle_, GetDeviceRelativePath(device_path_, file_path.value()), |
- media_task_runner_, &on_task_completed_event_, &on_shutdown_event_)); |
- worker->Run(); |
- return worker->get_file_info(file_info); |
-} |
- |
-scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> |
- MTPDeviceDelegateImplLinux::CreateFileEnumerator( |
- const FilePath& root, |
- bool recursive) { |
- if (root.value().empty() || !LazyInit()) { |
- return make_scoped_ptr(new FileSystemFileUtil::EmptyFileEnumerator()) |
- .PassAs<FileSystemFileUtil::AbstractFileEnumerator>(); |
- } |
- |
- scoped_refptr<ReadDirectoryWorker> worker(new ReadDirectoryWorker( |
- device_handle_, GetDeviceRelativePath(device_path_, root.value()), |
- media_task_runner_, &on_task_completed_event_, &on_shutdown_event_)); |
- worker->Run(); |
- |
- if (worker->get_file_entries().empty()) { |
- return make_scoped_ptr(new FileSystemFileUtil::EmptyFileEnumerator()) |
- .PassAs<FileSystemFileUtil::AbstractFileEnumerator>(); |
- } |
- |
- if (recursive) { |
- return make_scoped_ptr(new RecursiveMediaFileEnumerator( |
- device_handle_, media_task_runner_, worker->get_file_entries(), |
- &on_task_completed_event_, &on_shutdown_event_)) |
- .PassAs<FileSystemFileUtil::AbstractFileEnumerator>(); |
- } |
- return make_scoped_ptr(new MediaFileEnumerator(worker->get_file_entries())) |
- .PassAs<FileSystemFileUtil::AbstractFileEnumerator>(); |
-} |
- |
-PlatformFileError MTPDeviceDelegateImplLinux::CreateSnapshotFile( |
- const FilePath& device_file_path, |
- const FilePath& local_path, |
- PlatformFileInfo* file_info) { |
- if (!LazyInit()) |
- return base::PLATFORM_FILE_ERROR_FAILED; |
- |
- PlatformFileError error = GetFileInfo(device_file_path, file_info); |
- if (error != base::PLATFORM_FILE_OK) |
- return error; |
- |
- if (file_info->size <= 0 || file_info->size > kuint32max) |
- return base::PLATFORM_FILE_ERROR_FAILED; |
- |
- scoped_refptr<ReadFileWorker> worker(new ReadFileWorker( |
- device_handle_, |
- GetDeviceRelativePath(device_path_, device_file_path.value()), |
- file_info->size, local_path, media_task_runner_, |
- &on_task_completed_event_, &on_shutdown_event_)); |
- worker->Run(); |
- |
- if (!worker->Succeeded()) |
- return base::PLATFORM_FILE_ERROR_FAILED; |
- |
- // Modify the last modified time to null. This prevents the time stamp |
- // verfication in LocalFileStreamReader. |
- file_info->last_modified = base::Time(); |
- return base::PLATFORM_FILE_OK; |
-} |
- |
-SequencedTaskRunner* MTPDeviceDelegateImplLinux::GetMediaTaskRunner() { |
- return media_task_runner_.get(); |
-} |
- |
-void MTPDeviceDelegateImplLinux::CancelPendingTasksAndDeleteDelegate() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- // Caution: This function is called on the IO thread. Access only the thread |
- // safe member variables in this function. Do all the clean up operations in |
- // DeleteDelegateOnTaskRunner(). |
- on_shutdown_event_.Signal(); |
- on_task_completed_event_.Signal(); |
- media_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&MTPDeviceDelegateImplLinux::DeleteDelegateOnTaskRunner, |
- base::Unretained(this))); |
-} |
- |
-base::WeakPtr<fileapi::MTPDeviceDelegate> MTPDeviceDelegateImplLinux:: |
- GetAsWeakPtrOnIOThread() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- base::WeakPtr<fileapi::MTPDeviceDelegate> delegate = AsWeakPtr(); |
- // The weak pointer is instantiated on the IO thread, but only accessed on |
- // |media_task_runner_|. Therefore, detach from the current thread. |
- DetachFromThread(); |
- return delegate; |
-} |
- |
-MTPDeviceDelegateImplLinux::~MTPDeviceDelegateImplLinux() { |
- DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); |
- // Do all the clean up operations on DeleteDelegateOnTaskRunner(). |
-} |
- |
-bool MTPDeviceDelegateImplLinux::LazyInit() { |
- DCHECK(media_task_runner_); |
- DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); |
- |
- if (!device_handle_.empty()) |
- return true; // Already successfully initialized. |
- |
- std::string storage_name; |
- RemoveChars(device_path_, kRootPath, &storage_name); |
- DCHECK(!storage_name.empty()); |
- scoped_refptr<OpenStorageWorker> worker(new OpenStorageWorker( |
- storage_name, media_task_runner_, &on_task_completed_event_, |
- &on_shutdown_event_)); |
- worker->Run(); |
- device_handle_ = worker->device_handle(); |
- return !device_handle_.empty(); |
-} |
- |
-void MTPDeviceDelegateImplLinux::DeleteDelegateOnTaskRunner() { |
- DCHECK(media_task_runner_->RunsTasksOnCurrentThread()); |
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
- Bind(&CloseStorageOnUIThread, device_handle_)); |
- delete this; |
-} |
- |
-} // namespace chrome |