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