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 #ifndef CHROME_BROWSER_MEDIA_GALLERIES_LINUX_MTP_DEVICE_DELEGATE_IMPL_LINUX_H_ 6 #define CHROME_BROWSER_MEDIA_GALLERIES_LINUX_MTP_DEVICE_DELEGATE_IMPL_LINUX_H_ 7 8 #include <deque> 9 #include <map> 10 #include <set> 11 #include <string> 12 13 #include "base/callback.h" 14 #include "base/containers/scoped_ptr_hash_map.h" 15 #include "base/files/file_path.h" 16 #include "base/location.h" 17 #include "base/memory/scoped_ptr.h" 18 #include "base/memory/weak_ptr.h" 19 #include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h" 20 #include "content/public/browser/browser_thread.h" 21 #include "storage/browser/fileapi/async_file_util.h" 22 23 struct SnapshotRequestInfo; 24 25 // MTPDeviceDelegateImplLinux communicates with the media transfer protocol 26 // (MTP) device to complete file system operations. These operations are 27 // performed asynchronously. Instantiate this class per MTP device storage. 28 // MTPDeviceDelegateImplLinux lives on the IO thread. 29 // MTPDeviceDelegateImplLinux does a call-and-reply to the UI thread 30 // to dispatch the requests to MediaTransferProtocolManager. 31 class MTPDeviceDelegateImplLinux : public MTPDeviceAsyncDelegate { 32 private: 33 friend void CreateMTPDeviceAsyncDelegate( 34 const std::string&, 35 const CreateMTPDeviceAsyncDelegateCallback&); 36 37 enum InitializationState { 38 UNINITIALIZED = 0, 39 PENDING_INIT, 40 INITIALIZED 41 }; 42 43 // Used to represent pending task details. 44 struct PendingTaskInfo { 45 PendingTaskInfo(const base::FilePath& path, 46 content::BrowserThread::ID thread_id, 47 const tracked_objects::Location& location, 48 const base::Closure& task); 49 ~PendingTaskInfo(); 50 51 base::FilePath path; 52 base::FilePath cached_path; 53 const content::BrowserThread::ID thread_id; 54 const tracked_objects::Location location; 55 const base::Closure task; 56 }; 57 58 class MTPFileNode; 59 60 // Maps file ids to file nodes. 61 typedef std::map<uint32, MTPFileNode*> FileIdToMTPFileNodeMap; 62 63 // Maps file paths to file info. 64 typedef std::map<base::FilePath, storage::DirectoryEntry> FileInfoCache; 65 66 // Should only be called by CreateMTPDeviceAsyncDelegate() factory call. 67 // Defer the device initializations until the first file operation request. 68 // Do all the initializations in EnsureInitAndRunTask() function. 69 explicit MTPDeviceDelegateImplLinux(const std::string& device_location); 70 71 // Destructed via CancelPendingTasksAndDeleteDelegate(). 72 virtual ~MTPDeviceDelegateImplLinux(); 73 74 // MTPDeviceAsyncDelegate: 75 virtual void GetFileInfo(const base::FilePath& file_path, 76 const GetFileInfoSuccessCallback& success_callback, 77 const ErrorCallback& error_callback) OVERRIDE; 78 virtual void ReadDirectory( 79 const base::FilePath& root, 80 const ReadDirectorySuccessCallback& success_callback, 81 const ErrorCallback& error_callback) OVERRIDE; 82 virtual void CreateSnapshotFile( 83 const base::FilePath& device_file_path, 84 const base::FilePath& local_path, 85 const CreateSnapshotFileSuccessCallback& success_callback, 86 const ErrorCallback& error_callback) OVERRIDE; 87 virtual bool IsStreaming() OVERRIDE; 88 virtual void ReadBytes(const base::FilePath& device_file_path, 89 const scoped_refptr<net::IOBuffer>& buf, 90 int64 offset, 91 int buf_len, 92 const ReadBytesSuccessCallback& success_callback, 93 const ErrorCallback& error_callback) OVERRIDE; 94 virtual void CancelPendingTasksAndDeleteDelegate() OVERRIDE; 95 96 // The internal methods correspond to the similarly named methods above. 97 // The |root_node_| cache should be filled at this point. 98 virtual void GetFileInfoInternal( 99 const base::FilePath& file_path, 100 const GetFileInfoSuccessCallback& success_callback, 101 const ErrorCallback& error_callback); 102 virtual void ReadDirectoryInternal( 103 const base::FilePath& root, 104 const ReadDirectorySuccessCallback& success_callback, 105 const ErrorCallback& error_callback); 106 virtual void CreateSnapshotFileInternal( 107 const base::FilePath& device_file_path, 108 const base::FilePath& local_path, 109 const CreateSnapshotFileSuccessCallback& success_callback, 110 const ErrorCallback& error_callback); 111 virtual void ReadBytesInternal( 112 const base::FilePath& device_file_path, 113 net::IOBuffer* buf, int64 offset, int buf_len, 114 const ReadBytesSuccessCallback& success_callback, 115 const ErrorCallback& error_callback); 116 117 // Ensures the device is initialized for communication. 118 // If the device is already initialized, call RunTask(). 119 // 120 // If the device is uninitialized, store the |task_info| in a pending task 121 // queue and runs the pending tasks in the queue once the device is 122 // successfully initialized. 123 void EnsureInitAndRunTask(const PendingTaskInfo& task_info); 124 125 // Runs a task. If |task_info.path| is empty, or if the path is cached, runs 126 // the task immediately. 127 // Otherwise, fills the cache first before running the task. 128 // |task_info.task| runs on the UI thread. 129 void RunTask(const PendingTaskInfo& task_info); 130 131 // Writes data from the device to the snapshot file path based on the 132 // parameters in |current_snapshot_request_info_| by doing a call-and-reply to 133 // the UI thread. 134 // 135 // |snapshot_file_info| specifies the metadata details of the snapshot file. 136 void WriteDataIntoSnapshotFile(const base::File::Info& snapshot_file_info); 137 138 // Marks the current request as complete and call ProcessNextPendingRequest(). 139 void PendingRequestDone(); 140 141 // Processes the next pending request. 142 void ProcessNextPendingRequest(); 143 144 // Handles the device initialization event. |succeeded| indicates whether 145 // device initialization succeeded. 146 // 147 // If the device is successfully initialized, runs the next pending task. 148 void OnInitCompleted(bool succeeded); 149 150 // Called when GetFileInfo() succeeds. |file_info| specifies the 151 // requested file details. |success_callback| is invoked to notify the caller 152 // about the requested file details. 153 void OnDidGetFileInfo(const GetFileInfoSuccessCallback& success_callback, 154 const base::File::Info& file_info); 155 156 // Called when GetFileInfo() succeeds. GetFileInfo() is invoked to 157 // get the |dir_id| directory metadata details. |file_info| specifies the 158 // |dir_id| directory details. 159 // 160 // If |dir_id| is a directory, post a task on the UI thread to read the 161 // |dir_id| directory file entries. 162 // 163 // If |dir_id| is not a directory, |error_callback| is invoked to notify the 164 // caller about the file error and process the next pending request. 165 void OnDidGetFileInfoToReadDirectory( 166 uint32 dir_id, 167 const ReadDirectorySuccessCallback& success_callback, 168 const ErrorCallback& error_callback, 169 const base::File::Info& file_info); 170 171 // Called when GetFileInfo() succeeds. GetFileInfo() is invoked to 172 // create the snapshot file of |snapshot_request_info.device_file_path|. 173 // |file_info| specifies the device file metadata details. 174 // 175 // Posts a task on the UI thread to copy the data contents of the device file 176 // to the snapshot file. 177 void OnDidGetFileInfoToCreateSnapshotFile( 178 scoped_ptr<SnapshotRequestInfo> snapshot_request_info, 179 const base::File::Info& file_info); 180 181 // Called when ReadDirectory() succeeds. 182 // 183 // |dir_id| is the directory read. 184 // |success_callback| is invoked to notify the caller about the directory 185 // file entries. 186 // |file_list| contains the directory file entries with their file ids. 187 // |has_more| is true if there are more file entries to read. 188 void OnDidReadDirectory(uint32 dir_id, 189 const ReadDirectorySuccessCallback& success_callback, 190 const storage::AsyncFileUtil::EntryList& file_list, 191 bool has_more); 192 193 // Called when WriteDataIntoSnapshotFile() succeeds. 194 // 195 // |snapshot_file_info| specifies the snapshot file metadata details. 196 // 197 // |current_snapshot_request_info_.success_callback| is invoked to notify the 198 // caller about |snapshot_file_info|. 199 void OnDidWriteDataIntoSnapshotFile( 200 const base::File::Info& snapshot_file_info, 201 const base::FilePath& snapshot_file_path); 202 203 // Called when WriteDataIntoSnapshotFile() fails. 204 // 205 // |error| specifies the file error code. 206 // 207 // |current_snapshot_request_info_.error_callback| is invoked to notify the 208 // caller about |error|. 209 void OnWriteDataIntoSnapshotFileError(base::File::Error error); 210 211 // Called when ReadBytes() succeeds. 212 // 213 // |success_callback| is invoked to notify the caller about the read bytes. 214 // |bytes_read| is the number of bytes read. 215 void OnDidReadBytes(const ReadBytesSuccessCallback& success_callback, 216 const base::File::Info& file_info, int bytes_read); 217 218 // Called when FillFileCache() succeeds. 219 void OnDidFillFileCache(const base::FilePath& path, 220 const storage::AsyncFileUtil::EntryList& file_list, 221 bool has_more); 222 223 // Called when FillFileCache() fails. 224 void OnFillFileCacheFailed(base::File::Error error); 225 226 // Handles the device file |error| while operating on |file_id|. 227 // |error_callback| is invoked to notify the caller about the file error. 228 void HandleDeviceFileError(const ErrorCallback& error_callback, 229 uint32 file_id, 230 base::File::Error error); 231 232 // Given a full path, returns a non-empty sub-path that needs to be read into 233 // the cache if such a uncached path exists. 234 // |cached_path| is the portion of |path| that has had cache lookup attempts. 235 base::FilePath NextUncachedPathComponent( 236 const base::FilePath& path, 237 const base::FilePath& cached_path) const; 238 239 // Fills the file cache using the results from NextUncachedPathComponent(). 240 void FillFileCache(const base::FilePath& uncached_path); 241 242 // Given a full path, if it exists in the cache, writes the file's id to |id| 243 // and return true. 244 bool CachedPathToId(const base::FilePath& path, uint32* id) const; 245 246 // MTP device initialization state. 247 InitializationState init_state_; 248 249 // Used to make sure only one task is in progress at any time. 250 // Otherwise the browser will try to send too many requests at once and 251 // overload the device. 252 bool task_in_progress_; 253 254 // Registered file system device path. This path does not 255 // correspond to a real device path (e.g. "/usb:2,2:81282"). 256 const base::FilePath device_path_; 257 258 // MTP device storage name (e.g. "usb:2,2:81282"). 259 std::string storage_name_; 260 261 // A list of pending tasks that needs to be run when the device is 262 // initialized or when the current task in progress is complete. 263 std::deque<PendingTaskInfo> pending_tasks_; 264 265 // Used to track the current snapshot file request. A snapshot file is created 266 // incrementally. CreateSnapshotFile request reads the device file and writes 267 // to the snapshot file in chunks. In order to retain the order of the 268 // snapshot file requests, make sure there is only one active snapshot file 269 // request at any time. 270 scoped_ptr<SnapshotRequestInfo> current_snapshot_request_info_; 271 272 // A mapping for quick lookups into the |root_node_| tree structure. Since 273 // |root_node_| contains pointers to this map, it must be declared after this 274 // so destruction happens in the right order. 275 FileIdToMTPFileNodeMap file_id_to_node_map_; 276 277 // The root node of a tree-structure that caches the directory structure of 278 // the MTP device. 279 scoped_ptr<MTPFileNode> root_node_; 280 281 // A list of child nodes encountered while a ReadDirectory operation, which 282 // can return results over multiple callbacks, is in progress. 283 std::set<std::string> child_nodes_seen_; 284 285 // A cache to store file metadata for file entries read during a ReadDirectory 286 // operation. Used to service incoming GetFileInfo calls for the duration of 287 // the ReadDirectory operation. 288 FileInfoCache file_info_cache_; 289 290 // For callbacks that may run after destruction. 291 base::WeakPtrFactory<MTPDeviceDelegateImplLinux> weak_ptr_factory_; 292 293 DISALLOW_COPY_AND_ASSIGN(MTPDeviceDelegateImplLinux); 294 }; 295 296 #endif // CHROME_BROWSER_MEDIA_GALLERIES_LINUX_MTP_DEVICE_DELEGATE_IMPL_LINUX_H_ 297