OLD | NEW |
| (Empty) |
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 "webkit/browser/fileapi/file_system_context.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/single_thread_task_runner.h" | |
9 #include "base/stl_util.h" | |
10 #include "base/task_runner_util.h" | |
11 #include "net/url_request/url_request.h" | |
12 #include "url/gurl.h" | |
13 #include "webkit/browser/blob/file_stream_reader.h" | |
14 #include "webkit/browser/fileapi/copy_or_move_file_validator.h" | |
15 #include "webkit/browser/fileapi/external_mount_points.h" | |
16 #include "webkit/browser/fileapi/file_permission_policy.h" | |
17 #include "webkit/browser/fileapi/file_stream_writer.h" | |
18 #include "webkit/browser/fileapi/file_system_file_util.h" | |
19 #include "webkit/browser/fileapi/file_system_operation.h" | |
20 #include "webkit/browser/fileapi/file_system_operation_runner.h" | |
21 #include "webkit/browser/fileapi/file_system_options.h" | |
22 #include "webkit/browser/fileapi/file_system_quota_client.h" | |
23 #include "webkit/browser/fileapi/file_system_url.h" | |
24 #include "webkit/browser/fileapi/isolated_context.h" | |
25 #include "webkit/browser/fileapi/isolated_file_system_backend.h" | |
26 #include "webkit/browser/fileapi/mount_points.h" | |
27 #include "webkit/browser/fileapi/quota/quota_reservation.h" | |
28 #include "webkit/browser/fileapi/sandbox_file_system_backend.h" | |
29 #include "webkit/browser/quota/quota_manager_proxy.h" | |
30 #include "webkit/browser/quota/special_storage_policy.h" | |
31 #include "webkit/common/fileapi/file_system_info.h" | |
32 #include "webkit/common/fileapi/file_system_util.h" | |
33 | |
34 using storage::QuotaClient; | |
35 | |
36 namespace storage { | |
37 | |
38 namespace { | |
39 | |
40 QuotaClient* CreateQuotaClient( | |
41 FileSystemContext* context, | |
42 bool is_incognito) { | |
43 return new FileSystemQuotaClient(context, is_incognito); | |
44 } | |
45 | |
46 | |
47 void DidGetMetadataForResolveURL( | |
48 const base::FilePath& path, | |
49 const FileSystemContext::ResolveURLCallback& callback, | |
50 const FileSystemInfo& info, | |
51 base::File::Error error, | |
52 const base::File::Info& file_info) { | |
53 if (error != base::File::FILE_OK) { | |
54 if (error == base::File::FILE_ERROR_NOT_FOUND) { | |
55 callback.Run(base::File::FILE_OK, info, path, | |
56 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND); | |
57 } else { | |
58 callback.Run(error, FileSystemInfo(), base::FilePath(), | |
59 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND); | |
60 } | |
61 return; | |
62 } | |
63 callback.Run(error, info, path, file_info.is_directory ? | |
64 FileSystemContext::RESOLVED_ENTRY_DIRECTORY : | |
65 FileSystemContext::RESOLVED_ENTRY_FILE); | |
66 } | |
67 | |
68 void RelayResolveURLCallback( | |
69 scoped_refptr<base::MessageLoopProxy> message_loop, | |
70 const FileSystemContext::ResolveURLCallback& callback, | |
71 base::File::Error result, | |
72 const FileSystemInfo& info, | |
73 const base::FilePath& file_path, | |
74 FileSystemContext::ResolvedEntryType type) { | |
75 message_loop->PostTask( | |
76 FROM_HERE, base::Bind(callback, result, info, file_path, type)); | |
77 } | |
78 | |
79 } // namespace | |
80 | |
81 // static | |
82 int FileSystemContext::GetPermissionPolicy(FileSystemType type) { | |
83 switch (type) { | |
84 case kFileSystemTypeTemporary: | |
85 case kFileSystemTypePersistent: | |
86 case kFileSystemTypeSyncable: | |
87 return FILE_PERMISSION_SANDBOX; | |
88 | |
89 case kFileSystemTypeDrive: | |
90 case kFileSystemTypeNativeForPlatformApp: | |
91 case kFileSystemTypeNativeLocal: | |
92 case kFileSystemTypeCloudDevice: | |
93 case kFileSystemTypeProvided: | |
94 case kFileSystemTypeDeviceMediaAsFileStorage: | |
95 return FILE_PERMISSION_USE_FILE_PERMISSION; | |
96 | |
97 case kFileSystemTypeRestrictedNativeLocal: | |
98 return FILE_PERMISSION_READ_ONLY | | |
99 FILE_PERMISSION_USE_FILE_PERMISSION; | |
100 | |
101 case kFileSystemTypeDeviceMedia: | |
102 case kFileSystemTypeIphoto: | |
103 case kFileSystemTypeItunes: | |
104 case kFileSystemTypeNativeMedia: | |
105 case kFileSystemTypePicasa: | |
106 return FILE_PERMISSION_USE_FILE_PERMISSION; | |
107 | |
108 // Following types are only accessed via IsolatedFileSystem, and | |
109 // don't have their own permission policies. | |
110 case kFileSystemTypeDragged: | |
111 case kFileSystemTypeForTransientFile: | |
112 case kFileSystemTypePluginPrivate: | |
113 return FILE_PERMISSION_ALWAYS_DENY; | |
114 | |
115 // Following types only appear as mount_type, and will not be | |
116 // queried for their permission policies. | |
117 case kFileSystemTypeIsolated: | |
118 case kFileSystemTypeExternal: | |
119 return FILE_PERMISSION_ALWAYS_DENY; | |
120 | |
121 // Following types should not be used to access files by FileAPI clients. | |
122 case kFileSystemTypeTest: | |
123 case kFileSystemTypeSyncableForInternalSync: | |
124 case kFileSystemInternalTypeEnumEnd: | |
125 case kFileSystemInternalTypeEnumStart: | |
126 case kFileSystemTypeUnknown: | |
127 return FILE_PERMISSION_ALWAYS_DENY; | |
128 } | |
129 NOTREACHED(); | |
130 return FILE_PERMISSION_ALWAYS_DENY; | |
131 } | |
132 | |
133 FileSystemContext::FileSystemContext( | |
134 base::SingleThreadTaskRunner* io_task_runner, | |
135 base::SequencedTaskRunner* file_task_runner, | |
136 ExternalMountPoints* external_mount_points, | |
137 storage::SpecialStoragePolicy* special_storage_policy, | |
138 storage::QuotaManagerProxy* quota_manager_proxy, | |
139 ScopedVector<FileSystemBackend> additional_backends, | |
140 const std::vector<URLRequestAutoMountHandler>& auto_mount_handlers, | |
141 const base::FilePath& partition_path, | |
142 const FileSystemOptions& options) | |
143 : io_task_runner_(io_task_runner), | |
144 default_file_task_runner_(file_task_runner), | |
145 quota_manager_proxy_(quota_manager_proxy), | |
146 sandbox_delegate_( | |
147 new SandboxFileSystemBackendDelegate(quota_manager_proxy, | |
148 file_task_runner, | |
149 partition_path, | |
150 special_storage_policy, | |
151 options)), | |
152 sandbox_backend_(new SandboxFileSystemBackend(sandbox_delegate_.get())), | |
153 isolated_backend_(new IsolatedFileSystemBackend()), | |
154 plugin_private_backend_( | |
155 new PluginPrivateFileSystemBackend(file_task_runner, | |
156 partition_path, | |
157 special_storage_policy, | |
158 options)), | |
159 additional_backends_(additional_backends.Pass()), | |
160 auto_mount_handlers_(auto_mount_handlers), | |
161 external_mount_points_(external_mount_points), | |
162 partition_path_(partition_path), | |
163 is_incognito_(options.is_incognito()), | |
164 operation_runner_(new FileSystemOperationRunner(this)) { | |
165 RegisterBackend(sandbox_backend_.get()); | |
166 RegisterBackend(isolated_backend_.get()); | |
167 RegisterBackend(plugin_private_backend_.get()); | |
168 | |
169 for (ScopedVector<FileSystemBackend>::const_iterator iter = | |
170 additional_backends_.begin(); | |
171 iter != additional_backends_.end(); ++iter) { | |
172 RegisterBackend(*iter); | |
173 } | |
174 | |
175 if (quota_manager_proxy) { | |
176 // Quota client assumes all backends have registered. | |
177 quota_manager_proxy->RegisterClient(CreateQuotaClient( | |
178 this, options.is_incognito())); | |
179 } | |
180 | |
181 sandbox_backend_->Initialize(this); | |
182 isolated_backend_->Initialize(this); | |
183 plugin_private_backend_->Initialize(this); | |
184 for (ScopedVector<FileSystemBackend>::const_iterator iter = | |
185 additional_backends_.begin(); | |
186 iter != additional_backends_.end(); ++iter) { | |
187 (*iter)->Initialize(this); | |
188 } | |
189 | |
190 // Additional mount points must be added before regular system-wide | |
191 // mount points. | |
192 if (external_mount_points) | |
193 url_crackers_.push_back(external_mount_points); | |
194 url_crackers_.push_back(ExternalMountPoints::GetSystemInstance()); | |
195 url_crackers_.push_back(IsolatedContext::GetInstance()); | |
196 } | |
197 | |
198 bool FileSystemContext::DeleteDataForOriginOnFileTaskRunner( | |
199 const GURL& origin_url) { | |
200 DCHECK(default_file_task_runner()->RunsTasksOnCurrentThread()); | |
201 DCHECK(origin_url == origin_url.GetOrigin()); | |
202 | |
203 bool success = true; | |
204 for (FileSystemBackendMap::iterator iter = backend_map_.begin(); | |
205 iter != backend_map_.end(); | |
206 ++iter) { | |
207 FileSystemBackend* backend = iter->second; | |
208 if (!backend->GetQuotaUtil()) | |
209 continue; | |
210 if (backend->GetQuotaUtil()->DeleteOriginDataOnFileTaskRunner( | |
211 this, quota_manager_proxy(), origin_url, iter->first) | |
212 != base::File::FILE_OK) { | |
213 // Continue the loop, but record the failure. | |
214 success = false; | |
215 } | |
216 } | |
217 | |
218 return success; | |
219 } | |
220 | |
221 scoped_refptr<QuotaReservation> | |
222 FileSystemContext::CreateQuotaReservationOnFileTaskRunner( | |
223 const GURL& origin_url, | |
224 FileSystemType type) { | |
225 DCHECK(default_file_task_runner()->RunsTasksOnCurrentThread()); | |
226 FileSystemBackend* backend = GetFileSystemBackend(type); | |
227 if (!backend || !backend->GetQuotaUtil()) | |
228 return scoped_refptr<QuotaReservation>(); | |
229 return backend->GetQuotaUtil()->CreateQuotaReservationOnFileTaskRunner( | |
230 origin_url, type); | |
231 } | |
232 | |
233 void FileSystemContext::Shutdown() { | |
234 if (!io_task_runner_->RunsTasksOnCurrentThread()) { | |
235 io_task_runner_->PostTask( | |
236 FROM_HERE, base::Bind(&FileSystemContext::Shutdown, | |
237 make_scoped_refptr(this))); | |
238 return; | |
239 } | |
240 operation_runner_->Shutdown(); | |
241 } | |
242 | |
243 FileSystemQuotaUtil* | |
244 FileSystemContext::GetQuotaUtil(FileSystemType type) const { | |
245 FileSystemBackend* backend = GetFileSystemBackend(type); | |
246 if (!backend) | |
247 return NULL; | |
248 return backend->GetQuotaUtil(); | |
249 } | |
250 | |
251 AsyncFileUtil* FileSystemContext::GetAsyncFileUtil( | |
252 FileSystemType type) const { | |
253 FileSystemBackend* backend = GetFileSystemBackend(type); | |
254 if (!backend) | |
255 return NULL; | |
256 return backend->GetAsyncFileUtil(type); | |
257 } | |
258 | |
259 CopyOrMoveFileValidatorFactory* | |
260 FileSystemContext::GetCopyOrMoveFileValidatorFactory( | |
261 FileSystemType type, base::File::Error* error_code) const { | |
262 DCHECK(error_code); | |
263 *error_code = base::File::FILE_OK; | |
264 FileSystemBackend* backend = GetFileSystemBackend(type); | |
265 if (!backend) | |
266 return NULL; | |
267 return backend->GetCopyOrMoveFileValidatorFactory( | |
268 type, error_code); | |
269 } | |
270 | |
271 FileSystemBackend* FileSystemContext::GetFileSystemBackend( | |
272 FileSystemType type) const { | |
273 FileSystemBackendMap::const_iterator found = backend_map_.find(type); | |
274 if (found != backend_map_.end()) | |
275 return found->second; | |
276 NOTREACHED() << "Unknown filesystem type: " << type; | |
277 return NULL; | |
278 } | |
279 | |
280 WatcherManager* FileSystemContext::GetWatcherManager( | |
281 FileSystemType type) const { | |
282 FileSystemBackend* backend = GetFileSystemBackend(type); | |
283 if (!backend) | |
284 return NULL; | |
285 return backend->GetWatcherManager(type); | |
286 } | |
287 | |
288 bool FileSystemContext::IsSandboxFileSystem(FileSystemType type) const { | |
289 FileSystemBackendMap::const_iterator found = backend_map_.find(type); | |
290 return found != backend_map_.end() && found->second->GetQuotaUtil(); | |
291 } | |
292 | |
293 const UpdateObserverList* FileSystemContext::GetUpdateObservers( | |
294 FileSystemType type) const { | |
295 FileSystemBackend* backend = GetFileSystemBackend(type); | |
296 if (backend->GetQuotaUtil()) | |
297 return backend->GetQuotaUtil()->GetUpdateObservers(type); | |
298 return NULL; | |
299 } | |
300 | |
301 const ChangeObserverList* FileSystemContext::GetChangeObservers( | |
302 FileSystemType type) const { | |
303 FileSystemBackend* backend = GetFileSystemBackend(type); | |
304 if (backend->GetQuotaUtil()) | |
305 return backend->GetQuotaUtil()->GetChangeObservers(type); | |
306 return NULL; | |
307 } | |
308 | |
309 const AccessObserverList* FileSystemContext::GetAccessObservers( | |
310 FileSystemType type) const { | |
311 FileSystemBackend* backend = GetFileSystemBackend(type); | |
312 if (backend->GetQuotaUtil()) | |
313 return backend->GetQuotaUtil()->GetAccessObservers(type); | |
314 return NULL; | |
315 } | |
316 | |
317 void FileSystemContext::GetFileSystemTypes( | |
318 std::vector<FileSystemType>* types) const { | |
319 types->clear(); | |
320 for (FileSystemBackendMap::const_iterator iter = backend_map_.begin(); | |
321 iter != backend_map_.end(); ++iter) | |
322 types->push_back(iter->first); | |
323 } | |
324 | |
325 ExternalFileSystemBackend* | |
326 FileSystemContext::external_backend() const { | |
327 return static_cast<ExternalFileSystemBackend*>( | |
328 GetFileSystemBackend(kFileSystemTypeExternal)); | |
329 } | |
330 | |
331 void FileSystemContext::OpenFileSystem( | |
332 const GURL& origin_url, | |
333 FileSystemType type, | |
334 OpenFileSystemMode mode, | |
335 const OpenFileSystemCallback& callback) { | |
336 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
337 DCHECK(!callback.is_null()); | |
338 | |
339 if (!FileSystemContext::IsSandboxFileSystem(type)) { | |
340 // Disallow opening a non-sandboxed filesystem. | |
341 callback.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY); | |
342 return; | |
343 } | |
344 | |
345 FileSystemBackend* backend = GetFileSystemBackend(type); | |
346 if (!backend) { | |
347 callback.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY); | |
348 return; | |
349 } | |
350 | |
351 backend->ResolveURL( | |
352 CreateCrackedFileSystemURL(origin_url, type, base::FilePath()), | |
353 mode, | |
354 callback); | |
355 } | |
356 | |
357 void FileSystemContext::ResolveURL( | |
358 const FileSystemURL& url, | |
359 const ResolveURLCallback& callback) { | |
360 DCHECK(!callback.is_null()); | |
361 | |
362 // If not on IO thread, forward before passing the task to the backend. | |
363 if (!io_task_runner_->RunsTasksOnCurrentThread()) { | |
364 ResolveURLCallback relay_callback = | |
365 base::Bind(&RelayResolveURLCallback, | |
366 base::MessageLoopProxy::current(), callback); | |
367 io_task_runner_->PostTask( | |
368 FROM_HERE, | |
369 base::Bind(&FileSystemContext::ResolveURL, this, url, relay_callback)); | |
370 return; | |
371 } | |
372 | |
373 FileSystemBackend* backend = GetFileSystemBackend(url.type()); | |
374 if (!backend) { | |
375 callback.Run(base::File::FILE_ERROR_SECURITY, | |
376 FileSystemInfo(), base::FilePath(), | |
377 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND); | |
378 return; | |
379 } | |
380 | |
381 backend->ResolveURL( | |
382 url, | |
383 OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT, | |
384 base::Bind(&FileSystemContext::DidOpenFileSystemForResolveURL, | |
385 this, | |
386 url, | |
387 callback)); | |
388 } | |
389 | |
390 void FileSystemContext::AttemptAutoMountForURLRequest( | |
391 const net::URLRequest* url_request, | |
392 const std::string& storage_domain, | |
393 const StatusCallback& callback) { | |
394 FileSystemURL filesystem_url(url_request->url()); | |
395 if (filesystem_url.type() == kFileSystemTypeExternal) { | |
396 for (size_t i = 0; i < auto_mount_handlers_.size(); i++) { | |
397 if (auto_mount_handlers_[i].Run(url_request, filesystem_url, | |
398 storage_domain, callback)) { | |
399 return; | |
400 } | |
401 } | |
402 } | |
403 callback.Run(base::File::FILE_ERROR_NOT_FOUND); | |
404 } | |
405 | |
406 void FileSystemContext::DeleteFileSystem( | |
407 const GURL& origin_url, | |
408 FileSystemType type, | |
409 const StatusCallback& callback) { | |
410 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
411 DCHECK(origin_url == origin_url.GetOrigin()); | |
412 DCHECK(!callback.is_null()); | |
413 | |
414 FileSystemBackend* backend = GetFileSystemBackend(type); | |
415 if (!backend) { | |
416 callback.Run(base::File::FILE_ERROR_SECURITY); | |
417 return; | |
418 } | |
419 if (!backend->GetQuotaUtil()) { | |
420 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); | |
421 return; | |
422 } | |
423 | |
424 base::PostTaskAndReplyWithResult( | |
425 default_file_task_runner(), | |
426 FROM_HERE, | |
427 // It is safe to pass Unretained(quota_util) since context owns it. | |
428 base::Bind(&FileSystemQuotaUtil::DeleteOriginDataOnFileTaskRunner, | |
429 base::Unretained(backend->GetQuotaUtil()), | |
430 make_scoped_refptr(this), | |
431 base::Unretained(quota_manager_proxy()), | |
432 origin_url, | |
433 type), | |
434 callback); | |
435 } | |
436 | |
437 scoped_ptr<storage::FileStreamReader> FileSystemContext::CreateFileStreamReader( | |
438 const FileSystemURL& url, | |
439 int64 offset, | |
440 const base::Time& expected_modification_time) { | |
441 if (!url.is_valid()) | |
442 return scoped_ptr<storage::FileStreamReader>(); | |
443 FileSystemBackend* backend = GetFileSystemBackend(url.type()); | |
444 if (!backend) | |
445 return scoped_ptr<storage::FileStreamReader>(); | |
446 return backend->CreateFileStreamReader( | |
447 url, offset, expected_modification_time, this); | |
448 } | |
449 | |
450 scoped_ptr<FileStreamWriter> FileSystemContext::CreateFileStreamWriter( | |
451 const FileSystemURL& url, | |
452 int64 offset) { | |
453 if (!url.is_valid()) | |
454 return scoped_ptr<FileStreamWriter>(); | |
455 FileSystemBackend* backend = GetFileSystemBackend(url.type()); | |
456 if (!backend) | |
457 return scoped_ptr<FileStreamWriter>(); | |
458 return backend->CreateFileStreamWriter(url, offset, this); | |
459 } | |
460 | |
461 scoped_ptr<FileSystemOperationRunner> | |
462 FileSystemContext::CreateFileSystemOperationRunner() { | |
463 return make_scoped_ptr(new FileSystemOperationRunner(this)); | |
464 } | |
465 | |
466 FileSystemURL FileSystemContext::CrackURL(const GURL& url) const { | |
467 return CrackFileSystemURL(FileSystemURL(url)); | |
468 } | |
469 | |
470 FileSystemURL FileSystemContext::CreateCrackedFileSystemURL( | |
471 const GURL& origin, | |
472 FileSystemType type, | |
473 const base::FilePath& path) const { | |
474 return CrackFileSystemURL(FileSystemURL(origin, type, path)); | |
475 } | |
476 | |
477 #if defined(OS_CHROMEOS) | |
478 void FileSystemContext::EnableTemporaryFileSystemInIncognito() { | |
479 sandbox_backend_->set_enable_temporary_file_system_in_incognito(true); | |
480 } | |
481 #endif | |
482 | |
483 bool FileSystemContext::CanServeURLRequest(const FileSystemURL& url) const { | |
484 // We never support accessing files in isolated filesystems via an URL. | |
485 if (url.mount_type() == kFileSystemTypeIsolated) | |
486 return false; | |
487 #if defined(OS_CHROMEOS) | |
488 if (url.type() == kFileSystemTypeTemporary && | |
489 sandbox_backend_->enable_temporary_file_system_in_incognito()) { | |
490 return true; | |
491 } | |
492 #endif | |
493 return !is_incognito_ || !FileSystemContext::IsSandboxFileSystem(url.type()); | |
494 } | |
495 | |
496 bool FileSystemContext::ShouldFlushOnWriteCompletion( | |
497 FileSystemType type) const { | |
498 if (IsSandboxFileSystem(type)) { | |
499 // Disable Flush() for each write operation on SandboxFileSystems since it | |
500 // hurts the performance, assuming the FileSystems are stored in a local | |
501 // disk, we don't need to keep calling fsync() for it. | |
502 // On the other hand, other FileSystems that may stored on a removable media | |
503 // should be Flush()ed as soon as a write operation is completed, so that | |
504 // written data is saved over sudden media removal. | |
505 return false; | |
506 } | |
507 return true; | |
508 } | |
509 | |
510 void FileSystemContext::OpenPluginPrivateFileSystem( | |
511 const GURL& origin_url, | |
512 FileSystemType type, | |
513 const std::string& filesystem_id, | |
514 const std::string& plugin_id, | |
515 OpenFileSystemMode mode, | |
516 const StatusCallback& callback) { | |
517 DCHECK(plugin_private_backend_); | |
518 plugin_private_backend_->OpenPrivateFileSystem( | |
519 origin_url, type, filesystem_id, plugin_id, mode, callback); | |
520 } | |
521 | |
522 FileSystemContext::~FileSystemContext() { | |
523 } | |
524 | |
525 void FileSystemContext::DeleteOnCorrectThread() const { | |
526 if (!io_task_runner_->RunsTasksOnCurrentThread() && | |
527 io_task_runner_->DeleteSoon(FROM_HERE, this)) { | |
528 return; | |
529 } | |
530 delete this; | |
531 } | |
532 | |
533 FileSystemOperation* FileSystemContext::CreateFileSystemOperation( | |
534 const FileSystemURL& url, base::File::Error* error_code) { | |
535 if (!url.is_valid()) { | |
536 if (error_code) | |
537 *error_code = base::File::FILE_ERROR_INVALID_URL; | |
538 return NULL; | |
539 } | |
540 | |
541 FileSystemBackend* backend = GetFileSystemBackend(url.type()); | |
542 if (!backend) { | |
543 if (error_code) | |
544 *error_code = base::File::FILE_ERROR_FAILED; | |
545 return NULL; | |
546 } | |
547 | |
548 base::File::Error fs_error = base::File::FILE_OK; | |
549 FileSystemOperation* operation = | |
550 backend->CreateFileSystemOperation(url, this, &fs_error); | |
551 | |
552 if (error_code) | |
553 *error_code = fs_error; | |
554 return operation; | |
555 } | |
556 | |
557 FileSystemURL FileSystemContext::CrackFileSystemURL( | |
558 const FileSystemURL& url) const { | |
559 if (!url.is_valid()) | |
560 return FileSystemURL(); | |
561 | |
562 // The returned value in case there is no crackers which can crack the url. | |
563 // This is valid situation for non isolated/external file systems. | |
564 FileSystemURL current = url; | |
565 | |
566 // File system may be mounted multiple times (e.g., an isolated filesystem on | |
567 // top of an external filesystem). Hence cracking needs to be iterated. | |
568 for (;;) { | |
569 FileSystemURL cracked = current; | |
570 for (size_t i = 0; i < url_crackers_.size(); ++i) { | |
571 if (!url_crackers_[i]->HandlesFileSystemMountType(current.type())) | |
572 continue; | |
573 cracked = url_crackers_[i]->CrackFileSystemURL(current); | |
574 if (cracked.is_valid()) | |
575 break; | |
576 } | |
577 if (cracked == current) | |
578 break; | |
579 current = cracked; | |
580 } | |
581 return current; | |
582 } | |
583 | |
584 void FileSystemContext::RegisterBackend(FileSystemBackend* backend) { | |
585 const FileSystemType mount_types[] = { | |
586 kFileSystemTypeTemporary, | |
587 kFileSystemTypePersistent, | |
588 kFileSystemTypeIsolated, | |
589 kFileSystemTypeExternal, | |
590 }; | |
591 // Register file system backends for public mount types. | |
592 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(mount_types); ++j) { | |
593 if (backend->CanHandleType(mount_types[j])) { | |
594 const bool inserted = backend_map_.insert( | |
595 std::make_pair(mount_types[j], backend)).second; | |
596 DCHECK(inserted); | |
597 } | |
598 } | |
599 // Register file system backends for internal types. | |
600 for (int t = kFileSystemInternalTypeEnumStart + 1; | |
601 t < kFileSystemInternalTypeEnumEnd; ++t) { | |
602 FileSystemType type = static_cast<FileSystemType>(t); | |
603 if (backend->CanHandleType(type)) { | |
604 const bool inserted = backend_map_.insert( | |
605 std::make_pair(type, backend)).second; | |
606 DCHECK(inserted); | |
607 } | |
608 } | |
609 } | |
610 | |
611 void FileSystemContext::DidOpenFileSystemForResolveURL( | |
612 const FileSystemURL& url, | |
613 const FileSystemContext::ResolveURLCallback& callback, | |
614 const GURL& filesystem_root, | |
615 const std::string& filesystem_name, | |
616 base::File::Error error) { | |
617 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
618 | |
619 if (error != base::File::FILE_OK) { | |
620 callback.Run(error, FileSystemInfo(), base::FilePath(), | |
621 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND); | |
622 return; | |
623 } | |
624 | |
625 storage::FileSystemInfo info( | |
626 filesystem_name, filesystem_root, url.mount_type()); | |
627 | |
628 // Extract the virtual path not containing a filesystem type part from |url|. | |
629 base::FilePath parent = CrackURL(filesystem_root).virtual_path(); | |
630 base::FilePath child = url.virtual_path(); | |
631 base::FilePath path; | |
632 | |
633 if (parent.empty()) { | |
634 path = child; | |
635 } else if (parent != child) { | |
636 bool result = parent.AppendRelativePath(child, &path); | |
637 DCHECK(result); | |
638 } | |
639 | |
640 operation_runner()->GetMetadata( | |
641 url, base::Bind(&DidGetMetadataForResolveURL, path, callback, info)); | |
642 } | |
643 | |
644 } // namespace storage | |
OLD | NEW |