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