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/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 "webkit/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 static CallbackDispatcher* Create(const OpenFileCallback& callback, 77 const StatusCallback& error_callback) { 78 CallbackDispatcher* dispatcher = new CallbackDispatcher; 79 dispatcher->open_callback_ = callback; 80 dispatcher->error_callback_ = error_callback; 81 return dispatcher; 82 } 83 84 ~CallbackDispatcher() {} 85 86 void DidSucceed() { 87 status_callback_.Run(base::PLATFORM_FILE_OK); 88 } 89 90 void DidFail(base::PlatformFileError error_code) { 91 error_callback_.Run(error_code); 92 } 93 94 void DidReadMetadata( 95 const base::PlatformFileInfo& file_info) { 96 metadata_callback_.Run(file_info); 97 } 98 99 void DidCreateSnapshotFile( 100 const base::PlatformFileInfo& file_info, 101 const base::FilePath& platform_path, 102 int request_id) { 103 snapshot_callback_.Run(file_info, platform_path, request_id); 104 } 105 106 void DidReadDirectory( 107 const std::vector<fileapi::DirectoryEntry>& entries, 108 bool has_more) { 109 directory_callback_.Run(entries, has_more); 110 } 111 112 void DidOpenFileSystem(const std::string& name, 113 const GURL& root) { 114 filesystem_callback_.Run(name, root); 115 } 116 117 void DidResolveURL(const fileapi::FileSystemInfo& info, 118 const base::FilePath& file_path, 119 bool is_directory) { 120 resolve_callback_.Run(info, file_path, is_directory); 121 } 122 123 void DidWrite(int64 bytes, bool complete) { 124 write_callback_.Run(bytes, complete); 125 } 126 127 void DidOpenFile(base::PlatformFile file, 128 int file_open_id, 129 quota::QuotaLimitType quota_policy) { 130 open_callback_.Run(file, file_open_id, quota_policy); 131 } 132 133 private: 134 CallbackDispatcher() {} 135 136 StatusCallback status_callback_; 137 MetadataCallback metadata_callback_; 138 CreateSnapshotFileCallback snapshot_callback_; 139 ReadDirectoryCallback directory_callback_; 140 OpenFileSystemCallback filesystem_callback_; 141 ResolveURLCallback resolve_callback_; 142 WriteCallback write_callback_; 143 OpenFileCallback open_callback_; 144 145 StatusCallback error_callback_; 146 147 DISALLOW_COPY_AND_ASSIGN(CallbackDispatcher); 148 }; 149 150 FileSystemDispatcher::FileSystemDispatcher() { 151 } 152 153 FileSystemDispatcher::~FileSystemDispatcher() { 154 // Make sure we fire all the remaining callbacks. 155 for (IDMap<CallbackDispatcher, IDMapOwnPointer>::iterator 156 iter(&dispatchers_); !iter.IsAtEnd(); iter.Advance()) { 157 int request_id = iter.GetCurrentKey(); 158 CallbackDispatcher* dispatcher = iter.GetCurrentValue(); 159 DCHECK(dispatcher); 160 dispatcher->DidFail(base::PLATFORM_FILE_ERROR_ABORT); 161 dispatchers_.Remove(request_id); 162 } 163 } 164 165 bool FileSystemDispatcher::OnMessageReceived(const IPC::Message& msg) { 166 bool handled = true; 167 IPC_BEGIN_MESSAGE_MAP(FileSystemDispatcher, msg) 168 IPC_MESSAGE_HANDLER(FileSystemMsg_DidOpenFileSystem, OnDidOpenFileSystem) 169 IPC_MESSAGE_HANDLER(FileSystemMsg_DidResolveURL, OnDidResolveURL) 170 IPC_MESSAGE_HANDLER(FileSystemMsg_DidSucceed, OnDidSucceed) 171 IPC_MESSAGE_HANDLER(FileSystemMsg_DidReadDirectory, OnDidReadDirectory) 172 IPC_MESSAGE_HANDLER(FileSystemMsg_DidReadMetadata, OnDidReadMetadata) 173 IPC_MESSAGE_HANDLER(FileSystemMsg_DidCreateSnapshotFile, 174 OnDidCreateSnapshotFile) 175 IPC_MESSAGE_HANDLER(FileSystemMsg_DidFail, OnDidFail) 176 IPC_MESSAGE_HANDLER(FileSystemMsg_DidWrite, OnDidWrite) 177 IPC_MESSAGE_HANDLER(FileSystemMsg_DidOpenFile, OnDidOpenFile) 178 IPC_MESSAGE_UNHANDLED(handled = false) 179 IPC_END_MESSAGE_MAP() 180 return handled; 181 } 182 183 void FileSystemDispatcher::OpenFileSystem( 184 const GURL& origin_url, 185 fileapi::FileSystemType type, 186 const OpenFileSystemCallback& success_callback, 187 const StatusCallback& error_callback) { 188 int request_id = dispatchers_.Add( 189 CallbackDispatcher::Create(success_callback, error_callback)); 190 ChildThread::current()->Send(new FileSystemHostMsg_OpenFileSystem( 191 request_id, origin_url, type)); 192 } 193 194 void FileSystemDispatcher::ResolveURL( 195 const GURL& filesystem_url, 196 const ResolveURLCallback& success_callback, 197 const StatusCallback& error_callback) { 198 int request_id = dispatchers_.Add( 199 CallbackDispatcher::Create(success_callback, error_callback)); 200 ChildThread::current()->Send(new FileSystemHostMsg_ResolveURL( 201 request_id, filesystem_url)); 202 } 203 204 void FileSystemDispatcher::DeleteFileSystem( 205 const GURL& origin_url, 206 fileapi::FileSystemType type, 207 const StatusCallback& callback) { 208 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 209 ChildThread::current()->Send(new FileSystemHostMsg_DeleteFileSystem( 210 request_id, origin_url, type)); 211 } 212 213 void FileSystemDispatcher::Move( 214 const GURL& src_path, 215 const GURL& dest_path, 216 const StatusCallback& callback) { 217 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 218 ChildThread::current()->Send(new FileSystemHostMsg_Move( 219 request_id, src_path, dest_path)); 220 } 221 222 void FileSystemDispatcher::Copy( 223 const GURL& src_path, 224 const GURL& dest_path, 225 const StatusCallback& callback) { 226 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 227 ChildThread::current()->Send(new FileSystemHostMsg_Copy( 228 request_id, src_path, dest_path)); 229 } 230 231 void FileSystemDispatcher::Remove( 232 const GURL& path, 233 bool recursive, 234 const StatusCallback& callback) { 235 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 236 ChildThread::current()->Send( 237 new FileSystemHostMsg_Remove(request_id, path, recursive)); 238 } 239 240 void FileSystemDispatcher::ReadMetadata( 241 const GURL& path, 242 const MetadataCallback& success_callback, 243 const StatusCallback& error_callback) { 244 int request_id = dispatchers_.Add( 245 CallbackDispatcher::Create(success_callback, error_callback)); 246 ChildThread::current()->Send( 247 new FileSystemHostMsg_ReadMetadata(request_id, path)); 248 } 249 250 void FileSystemDispatcher::CreateFile( 251 const GURL& path, 252 bool exclusive, 253 const StatusCallback& callback) { 254 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 255 ChildThread::current()->Send(new FileSystemHostMsg_Create( 256 request_id, path, exclusive, 257 false /* is_directory */, false /* recursive */)); 258 } 259 260 void FileSystemDispatcher::CreateDirectory( 261 const GURL& path, 262 bool exclusive, 263 bool recursive, 264 const StatusCallback& callback) { 265 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 266 ChildThread::current()->Send(new FileSystemHostMsg_Create( 267 request_id, path, exclusive, true /* is_directory */, recursive)); 268 } 269 270 void FileSystemDispatcher::Exists( 271 const GURL& path, 272 bool is_directory, 273 const StatusCallback& callback) { 274 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 275 ChildThread::current()->Send( 276 new FileSystemHostMsg_Exists(request_id, path, is_directory)); 277 } 278 279 void FileSystemDispatcher::ReadDirectory( 280 const GURL& path, 281 const ReadDirectoryCallback& success_callback, 282 const StatusCallback& error_callback) { 283 int request_id = dispatchers_.Add( 284 CallbackDispatcher::Create(success_callback, error_callback)); 285 ChildThread::current()->Send( 286 new FileSystemHostMsg_ReadDirectory(request_id, path)); 287 } 288 289 void FileSystemDispatcher::Truncate( 290 const GURL& path, 291 int64 offset, 292 int* request_id_out, 293 const StatusCallback& callback) { 294 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 295 ChildThread::current()->Send( 296 new FileSystemHostMsg_Truncate(request_id, path, offset)); 297 298 if (request_id_out) 299 *request_id_out = request_id; 300 } 301 302 void FileSystemDispatcher::WriteDeprecated( 303 const GURL& path, 304 const GURL& blob_url, 305 int64 offset, 306 int* request_id_out, 307 const WriteCallback& success_callback, 308 const StatusCallback& error_callback) { 309 int request_id = dispatchers_.Add( 310 CallbackDispatcher::Create(success_callback, error_callback)); 311 ChildThread::current()->Send( 312 new FileSystemHostMsg_WriteDeprecated(request_id, path, 313 blob_url, offset)); 314 315 if (request_id_out) 316 *request_id_out = request_id; 317 } 318 319 void FileSystemDispatcher::Write( 320 const GURL& path, 321 const std::string& blob_id, 322 int64 offset, 323 int* request_id_out, 324 const WriteCallback& success_callback, 325 const StatusCallback& error_callback) { 326 int request_id = dispatchers_.Add( 327 CallbackDispatcher::Create(success_callback, error_callback)); 328 ChildThread::current()->Send( 329 new FileSystemHostMsg_Write(request_id, path, blob_id, offset)); 330 331 if (request_id_out) 332 *request_id_out = request_id; 333 } 334 335 void FileSystemDispatcher::Cancel( 336 int request_id_to_cancel, 337 const StatusCallback& callback) { 338 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 339 ChildThread::current()->Send(new FileSystemHostMsg_CancelWrite( 340 request_id, request_id_to_cancel)); 341 } 342 343 void FileSystemDispatcher::TouchFile( 344 const GURL& path, 345 const base::Time& last_access_time, 346 const base::Time& last_modified_time, 347 const StatusCallback& callback) { 348 int request_id = dispatchers_.Add(CallbackDispatcher::Create(callback)); 349 ChildThread::current()->Send( 350 new FileSystemHostMsg_TouchFile( 351 request_id, path, last_access_time, last_modified_time)); 352 } 353 354 void FileSystemDispatcher::CreateSnapshotFile( 355 const GURL& file_path, 356 const CreateSnapshotFileCallback& success_callback, 357 const StatusCallback& error_callback) { 358 int request_id = dispatchers_.Add( 359 CallbackDispatcher::Create(success_callback, error_callback)); 360 ChildThread::current()->Send( 361 new FileSystemHostMsg_CreateSnapshotFile( 362 request_id, file_path)); 363 } 364 365 void FileSystemDispatcher::OnDidOpenFileSystem(int request_id, 366 const std::string& name, 367 const GURL& root) { 368 DCHECK(root.is_valid()); 369 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 370 DCHECK(dispatcher); 371 dispatcher->DidOpenFileSystem(name, root); 372 dispatchers_.Remove(request_id); 373 } 374 375 void FileSystemDispatcher::OnDidResolveURL(int request_id, 376 const fileapi::FileSystemInfo& info, 377 const base::FilePath& file_path, 378 bool is_directory) { 379 DCHECK(info.root_url.is_valid()); 380 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 381 DCHECK(dispatcher); 382 dispatcher->DidResolveURL(info, file_path, is_directory); 383 dispatchers_.Remove(request_id); 384 } 385 386 void FileSystemDispatcher::OnDidSucceed(int request_id) { 387 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 388 DCHECK(dispatcher); 389 dispatcher->DidSucceed(); 390 dispatchers_.Remove(request_id); 391 } 392 393 void FileSystemDispatcher::OnDidReadMetadata( 394 int request_id, const base::PlatformFileInfo& file_info) { 395 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 396 DCHECK(dispatcher); 397 dispatcher->DidReadMetadata(file_info); 398 dispatchers_.Remove(request_id); 399 } 400 401 void FileSystemDispatcher::OnDidCreateSnapshotFile( 402 int request_id, const base::PlatformFileInfo& file_info, 403 const base::FilePath& platform_path) { 404 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 405 DCHECK(dispatcher); 406 dispatcher->DidCreateSnapshotFile(file_info, platform_path, request_id); 407 dispatchers_.Remove(request_id); 408 } 409 410 void FileSystemDispatcher::OnDidReadDirectory( 411 int request_id, 412 const std::vector<fileapi::DirectoryEntry>& entries, 413 bool has_more) { 414 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 415 DCHECK(dispatcher); 416 dispatcher->DidReadDirectory(entries, has_more); 417 dispatchers_.Remove(request_id); 418 } 419 420 void FileSystemDispatcher::OnDidFail( 421 int request_id, base::PlatformFileError error_code) { 422 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 423 DCHECK(dispatcher); 424 dispatcher->DidFail(error_code); 425 dispatchers_.Remove(request_id); 426 } 427 428 void FileSystemDispatcher::OnDidWrite( 429 int request_id, int64 bytes, bool complete) { 430 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 431 DCHECK(dispatcher); 432 dispatcher->DidWrite(bytes, complete); 433 if (complete) 434 dispatchers_.Remove(request_id); 435 } 436 437 void FileSystemDispatcher::OnDidOpenFile( 438 int request_id, 439 IPC::PlatformFileForTransit file, 440 int file_open_id, 441 quota::QuotaLimitType quota_policy) { 442 CallbackDispatcher* dispatcher = dispatchers_.Lookup(request_id); 443 DCHECK(dispatcher); 444 dispatcher->DidOpenFile(IPC::PlatformFileForTransitToPlatformFile(file), 445 file_open_id, 446 quota_policy); 447 dispatchers_.Remove(request_id); 448 } 449 450 } // namespace content 451