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 "content/child/fileapi/file_system_dispatcher.h" 6 7 #include "base/callback.h" 8 #include "base/files/file_util.h" 9 #include "base/message_loop/message_loop_proxy.h" 10 #include "base/process/process.h" 11 #include "content/child/child_thread.h" 12 #include "content/common/fileapi/file_system_messages.h" 13 #include "storage/common/fileapi/file_system_info.h" 14 15 namespace content { 16 17 class FileSystemDispatcher::CallbackDispatcher { 18 public: 19 typedef CallbackDispatcher self; 20 typedef FileSystemDispatcher::StatusCallback StatusCallback; 21 typedef FileSystemDispatcher::MetadataCallback MetadataCallback; 22 typedef FileSystemDispatcher::ReadDirectoryCallback ReadDirectoryCallback; 23 typedef FileSystemDispatcher::OpenFileSystemCallback OpenFileSystemCallback; 24 typedef FileSystemDispatcher::ResolveURLCallback ResolveURLCallback; 25 typedef FileSystemDispatcher::WriteCallback WriteCallback; 26 typedef FileSystemDispatcher::OpenFileCallback OpenFileCallback; 27 28 static CallbackDispatcher* Create(const StatusCallback& callback) { 29 CallbackDispatcher* dispatcher = new CallbackDispatcher; 30 dispatcher->status_callback_ = callback; 31 dispatcher->error_callback_ = callback; 32 return dispatcher; 33 } 34 static CallbackDispatcher* Create(const MetadataCallback& callback, 35 const StatusCallback& error_callback) { 36 CallbackDispatcher* dispatcher = new CallbackDispatcher; 37 dispatcher->metadata_callback_ = callback; 38 dispatcher->error_callback_ = error_callback; 39 return dispatcher; 40 } 41 static CallbackDispatcher* Create(const CreateSnapshotFileCallback& callback, 42 const StatusCallback& error_callback) { 43 CallbackDispatcher* dispatcher = new CallbackDispatcher; 44 dispatcher->snapshot_callback_ = callback; 45 dispatcher->error_callback_ = error_callback; 46 return dispatcher; 47 } 48 static CallbackDispatcher* Create(const ReadDirectoryCallback& callback, 49 const StatusCallback& error_callback) { 50 CallbackDispatcher* dispatcher = new CallbackDispatcher; 51 dispatcher->directory_callback_ = callback; 52 dispatcher->error_callback_ = error_callback; 53 return dispatcher; 54 } 55 static CallbackDispatcher* Create(const OpenFileSystemCallback& callback, 56 const StatusCallback& error_callback) { 57 CallbackDispatcher* dispatcher = new CallbackDispatcher; 58 dispatcher->filesystem_callback_ = callback; 59 dispatcher->error_callback_ = error_callback; 60 return dispatcher; 61 } 62 static CallbackDispatcher* Create(const ResolveURLCallback& callback, 63 const StatusCallback& error_callback) { 64 CallbackDispatcher* dispatcher = new CallbackDispatcher; 65 dispatcher->resolve_callback_ = callback; 66 dispatcher->error_callback_ = error_callback; 67 return dispatcher; 68 } 69 static CallbackDispatcher* Create(const WriteCallback& callback, 70 const StatusCallback& error_callback) { 71 CallbackDispatcher* dispatcher = new CallbackDispatcher; 72 dispatcher->write_callback_ = callback; 73 dispatcher->error_callback_ = error_callback; 74 return dispatcher; 75 } 76 77 ~CallbackDispatcher() {} 78 79 void DidSucceed() { 80 status_callback_.Run(base::File::FILE_OK); 81 } 82 83 void DidFail(base::File::Error error_code) { 84 error_callback_.Run(error_code); 85 } 86 87 void DidReadMetadata( 88 const base::File::Info& file_info) { 89 metadata_callback_.Run(file_info); 90 } 91 92 void DidCreateSnapshotFile( 93 const base::File::Info& file_info, 94 const base::FilePath& platform_path, 95 int request_id) { 96 snapshot_callback_.Run(file_info, platform_path, request_id); 97 } 98 99 void DidReadDirectory(const std::vector<storage::DirectoryEntry>& entries, 100 bool has_more) { 101 directory_callback_.Run(entries, has_more); 102 } 103 104 void DidOpenFileSystem(const std::string& name, 105 const GURL& root) { 106 filesystem_callback_.Run(name, root); 107 } 108 109 void DidResolveURL(const storage::FileSystemInfo& info, 110 const base::FilePath& file_path, 111 bool is_directory) { 112 resolve_callback_.Run(info, file_path, is_directory); 113 } 114 115 void DidWrite(int64 bytes, bool complete) { 116 write_callback_.Run(bytes, complete); 117 } 118 119 private: 120 CallbackDispatcher() {} 121 122 StatusCallback status_callback_; 123 MetadataCallback metadata_callback_; 124 CreateSnapshotFileCallback snapshot_callback_; 125 ReadDirectoryCallback directory_callback_; 126 OpenFileSystemCallback filesystem_callback_; 127 ResolveURLCallback resolve_callback_; 128 WriteCallback write_callback_; 129 130 StatusCallback error_callback_; 131 132 DISALLOW_COPY_AND_ASSIGN(CallbackDispatcher); 133 }; 134 135 FileSystemDispatcher::FileSystemDispatcher() { 136 } 137 138 FileSystemDispatcher::~FileSystemDispatcher() { 139 // Make sure we fire all the remaining callbacks. 140 for (IDMap<CallbackDispatcher, IDMapOwnPointer>::iterator 141 iter(&dispatchers_); !iter.IsAtEnd(); iter.Advance()) { 142 int request_id = iter.GetCurrentKey(); 143 CallbackDispatcher* dispatcher = iter.GetCurrentValue(); 144 DCHECK(dispatcher); 145 dispatcher->DidFail(base::File::FILE_ERROR_ABORT); 146 dispatchers_.Remove(request_id); 147 } 148 } 149 150 bool FileSystemDispatcher::OnMessageReceived(const IPC::Message& msg) { 151 bool handled = true; 152 IPC_BEGIN_MESSAGE_MAP(FileSystemDispatcher, msg) 153 IPC_MESSAGE_HANDLER(FileSystemMsg_DidOpenFileSystem, OnDidOpenFileSystem) 154 IPC_MESSAGE_HANDLER(FileSystemMsg_DidResolveURL, OnDidResolveURL) 155 IPC_MESSAGE_HANDLER(FileSystemMsg_DidSucceed, OnDidSucceed) 156 IPC_MESSAGE_HANDLER(FileSystemMsg_DidReadDirectory, OnDidReadDirectory) 157 IPC_MESSAGE_HANDLER(FileSystemMsg_DidReadMetadata, OnDidReadMetadata) 158 IPC_MESSAGE_HANDLER(FileSystemMsg_DidCreateSnapshotFile, 159 OnDidCreateSnapshotFile) 160 IPC_MESSAGE_HANDLER(FileSystemMsg_DidFail, OnDidFail) 161 IPC_MESSAGE_HANDLER(FileSystemMsg_DidWrite, OnDidWrite) 162 IPC_MESSAGE_UNHANDLED(handled = false) 163 IPC_END_MESSAGE_MAP() 164 return handled; 165 } 166 167 void FileSystemDispatcher::OpenFileSystem( 168 const GURL& origin_url, 169 storage::FileSystemType type, 170 const OpenFileSystemCallback& success_callback, 171 const StatusCallback& error_callback) { 172 int request_id = dispatchers_.Add( 173 CallbackDispatcher::Create(success_callback, error_callback)); 174 ChildThread::current()->Send(new FileSystemHostMsg_OpenFileSystem( 175 request_id, origin_url, type)); 176 } 177 178 void FileSystemDispatcher::ResolveURL( 179 const GURL& filesystem_url, 180 const ResolveURLCallback& success_callback, 181 const StatusCallback& error_callback) { 182 int request_id = dispatchers_.Add( 183 CallbackDispatcher::Create(success_callback, error_callback)); 184 ChildThread::current()->Send(new FileSystemHostMsg_ResolveURL( 185 request_id, filesystem_url)); 186 } 187 188 void FileSystemDispatcher::DeleteFileSystem(const GURL& origin_url, 189 storage::FileSystemType type, 190 const StatusCallback& callback) { 191 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 192 ChildThread::current()->Send(new FileSystemHostMsg_DeleteFileSystem( 193 request_id, origin_url, type)); 194 } 195 196 void FileSystemDispatcher::Move( 197 const GURL& src_path, 198 const GURL& dest_path, 199 const StatusCallback& callback) { 200 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 201 ChildThread::current()->Send(new FileSystemHostMsg_Move( 202 request_id, src_path, dest_path)); 203 } 204 205 void FileSystemDispatcher::Copy( 206 const GURL& src_path, 207 const GURL& dest_path, 208 const StatusCallback& callback) { 209 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 210 ChildThread::current()->Send(new FileSystemHostMsg_Copy( 211 request_id, src_path, dest_path)); 212 } 213 214 void FileSystemDispatcher::Remove( 215 const GURL& path, 216 bool recursive, 217 const StatusCallback& callback) { 218 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 219 ChildThread::current()->Send( 220 new FileSystemHostMsg_Remove(request_id, path, recursive)); 221 } 222 223 void FileSystemDispatcher::ReadMetadata( 224 const GURL& path, 225 const MetadataCallback& success_callback, 226 const StatusCallback& error_callback) { 227 int request_id = dispatchers_.Add( 228 CallbackDispatcher::Create(success_callback, error_callback)); 229 ChildThread::current()->Send( 230 new FileSystemHostMsg_ReadMetadata(request_id, path)); 231 } 232 233 void FileSystemDispatcher::CreateFile( 234 const GURL& path, 235 bool exclusive, 236 const StatusCallback& callback) { 237 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 238 ChildThread::current()->Send(new FileSystemHostMsg_Create( 239 request_id, path, exclusive, 240 false /* is_directory */, false /* recursive */)); 241 } 242 243 void FileSystemDispatcher::CreateDirectory( 244 const GURL& path, 245 bool exclusive, 246 bool recursive, 247 const StatusCallback& callback) { 248 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 249 ChildThread::current()->Send(new FileSystemHostMsg_Create( 250 request_id, path, exclusive, true /* is_directory */, recursive)); 251 } 252 253 void FileSystemDispatcher::Exists( 254 const GURL& path, 255 bool is_directory, 256 const StatusCallback& callback) { 257 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 258 ChildThread::current()->Send( 259 new FileSystemHostMsg_Exists(request_id, path, is_directory)); 260 } 261 262 void FileSystemDispatcher::ReadDirectory( 263 const GURL& path, 264 const ReadDirectoryCallback& success_callback, 265 const StatusCallback& error_callback) { 266 int request_id = dispatchers_.Add( 267 CallbackDispatcher::Create(success_callback, error_callback)); 268 ChildThread::current()->Send( 269 new FileSystemHostMsg_ReadDirectory(request_id, path)); 270 } 271 272 void FileSystemDispatcher::Truncate( 273 const GURL& path, 274 int64 offset, 275 int* request_id_out, 276 const StatusCallback& callback) { 277 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 278 ChildThread::current()->Send( 279 new FileSystemHostMsg_Truncate(request_id, path, offset)); 280 281 if (request_id_out) 282 *request_id_out = request_id; 283 } 284 285 void FileSystemDispatcher::Write( 286 const GURL& path, 287 const std::string& blob_id, 288 int64 offset, 289 int* request_id_out, 290 const WriteCallback& success_callback, 291 const StatusCallback& error_callback) { 292 int request_id = dispatchers_.Add( 293 CallbackDispatcher::Create(success_callback, error_callback)); 294 ChildThread::current()->Send( 295 new FileSystemHostMsg_Write(request_id, path, blob_id, offset)); 296 297 if (request_id_out) 298 *request_id_out = request_id; 299 } 300 301 void FileSystemDispatcher::Cancel( 302 int request_id_to_cancel, 303 const StatusCallback& callback) { 304 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 305 ChildThread::current()->Send(new FileSystemHostMsg_CancelWrite( 306 request_id, request_id_to_cancel)); 307 } 308 309 void FileSystemDispatcher::TouchFile( 310 const GURL& path, 311 const base::Time& last_access_time, 312 const base::Time& last_modified_time, 313 const StatusCallback& callback) { 314 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 315 ChildThread::current()->Send( 316 new FileSystemHostMsg_TouchFile( 317 request_id, path, last_access_time, last_modified_time)); 318 } 319 320 void FileSystemDispatcher::CreateSnapshotFile( 321 const GURL& file_path, 322 const CreateSnapshotFileCallback& success_callback, 323 const StatusCallback& error_callback) { 324 int request_id = dispatchers_.Add( 325 CallbackDispatcher::Create(success_callback, error_callback)); 326 ChildThread::current()->Send( 327 new FileSystemHostMsg_CreateSnapshotFile( 328 request_id, file_path)); 329 } 330 331 void FileSystemDispatcher::OnDidOpenFileSystem(int request_id, 332 const std::string& name, 333 const GURL& root) { 334 DCHECK(root.is_valid()); 335 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 336 DCHECK(dispatcher); 337 dispatcher->DidOpenFileSystem(name, root); 338 dispatchers_.Remove(request_id); 339 } 340 341 void FileSystemDispatcher::OnDidResolveURL(int request_id, 342 const storage::FileSystemInfo& info, 343 const base::FilePath& file_path, 344 bool is_directory) { 345 DCHECK(info.root_url.is_valid()); 346 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 347 DCHECK(dispatcher); 348 dispatcher->DidResolveURL(info, file_path, is_directory); 349 dispatchers_.Remove(request_id); 350 } 351 352 void FileSystemDispatcher::OnDidSucceed(int request_id) { 353 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 354 DCHECK(dispatcher); 355 dispatcher->DidSucceed(); 356 dispatchers_.Remove(request_id); 357 } 358 359 void FileSystemDispatcher::OnDidReadMetadata( 360 int request_id, const base::File::Info& file_info) { 361 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 362 DCHECK(dispatcher); 363 dispatcher->DidReadMetadata(file_info); 364 dispatchers_.Remove(request_id); 365 } 366 367 void FileSystemDispatcher::OnDidCreateSnapshotFile( 368 int request_id, const base::File::Info& file_info, 369 const base::FilePath& platform_path) { 370 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 371 DCHECK(dispatcher); 372 dispatcher->DidCreateSnapshotFile(file_info, platform_path, request_id); 373 dispatchers_.Remove(request_id); 374 } 375 376 void FileSystemDispatcher::OnDidReadDirectory( 377 int request_id, 378 const std::vector<storage::DirectoryEntry>& entries, 379 bool has_more) { 380 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 381 DCHECK(dispatcher); 382 dispatcher->DidReadDirectory(entries, has_more); 383 if (!has_more) 384 dispatchers_.Remove(request_id); 385 } 386 387 void FileSystemDispatcher::OnDidFail( 388 int request_id, base::File::Error error_code) { 389 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 390 DCHECK(dispatcher); 391 dispatcher->DidFail(error_code); 392 dispatchers_.Remove(request_id); 393 } 394 395 void FileSystemDispatcher::OnDidWrite( 396 int request_id, int64 bytes, bool complete) { 397 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 398 DCHECK(dispatcher); 399 dispatcher->DidWrite(bytes, complete); 400 if (complete) 401 dispatchers_.Remove(request_id); 402 } 403 404 } // namespace content 405