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 AccessObserverList* FileSystemContext::GetAccessObservers( | |
302 FileSystemType type) const { | |
303 FileSystemBackend* backend = GetFileSystemBackend(type); | |
304 if (backend->GetQuotaUtil()) | |
305 return backend->GetQuotaUtil()->GetAccessObservers(type); | |
306 return NULL; | |
307 } | |
308 | |
309 void FileSystemContext::GetFileSystemTypes( | |
310 std::vector<FileSystemType>* types) const { | |
311 types->clear(); | |
312 for (FileSystemBackendMap::const_iterator iter = backend_map_.begin(); | |
313 iter != backend_map_.end(); ++iter) | |
314 types->push_back(iter->first); | |
315 } | |
316 | |
317 ExternalFileSystemBackend* | |
318 FileSystemContext::external_backend() const { | |
319 return static_cast<ExternalFileSystemBackend*>( | |
320 GetFileSystemBackend(kFileSystemTypeExternal)); | |
321 } | |
322 | |
323 void FileSystemContext::OpenFileSystem( | |
324 const GURL& origin_url, | |
325 FileSystemType type, | |
326 OpenFileSystemMode mode, | |
327 const OpenFileSystemCallback& callback) { | |
328 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
329 DCHECK(!callback.is_null()); | |
330 | |
331 if (!FileSystemContext::IsSandboxFileSystem(type)) { | |
332 // Disallow opening a non-sandboxed filesystem. | |
333 callback.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY); | |
334 return; | |
335 } | |
336 | |
337 FileSystemBackend* backend = GetFileSystemBackend(type); | |
338 if (!backend) { | |
339 callback.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY); | |
340 return; | |
341 } | |
342 | |
343 backend->ResolveURL( | |
344 CreateCrackedFileSystemURL(origin_url, type, base::FilePath()), | |
345 mode, | |
346 callback); | |
347 } | |
348 | |
349 void FileSystemContext::ResolveURL( | |
350 const FileSystemURL& url, | |
351 const ResolveURLCallback& callback) { | |
352 DCHECK(!callback.is_null()); | |
353 | |
354 // If not on IO thread, forward before passing the task to the backend. | |
355 if (!io_task_runner_->RunsTasksOnCurrentThread()) { | |
356 ResolveURLCallback relay_callback = | |
357 base::Bind(&RelayResolveURLCallback, | |
358 base::MessageLoopProxy::current(), callback); | |
359 io_task_runner_->PostTask( | |
360 FROM_HERE, | |
361 base::Bind(&FileSystemContext::ResolveURL, this, url, relay_callback)); | |
362 return; | |
363 } | |
364 | |
365 FileSystemBackend* backend = GetFileSystemBackend(url.type()); | |
366 if (!backend) { | |
367 callback.Run(base::File::FILE_ERROR_SECURITY, | |
368 FileSystemInfo(), base::FilePath(), | |
369 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND); | |
370 return; | |
371 } | |
372 | |
373 backend->ResolveURL( | |
374 url, | |
375 OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT, | |
376 base::Bind(&FileSystemContext::DidOpenFileSystemForResolveURL, | |
377 this, | |
378 url, | |
379 callback)); | |
380 } | |
381 | |
382 void FileSystemContext::AttemptAutoMountForURLRequest( | |
383 const net::URLRequest* url_request, | |
384 const std::string& storage_domain, | |
385 const StatusCallback& callback) { | |
386 FileSystemURL filesystem_url(url_request->url()); | |
387 if (filesystem_url.type() == kFileSystemTypeExternal) { | |
388 for (size_t i = 0; i < auto_mount_handlers_.size(); i++) { | |
389 if (auto_mount_handlers_[i].Run(url_request, filesystem_url, | |
390 storage_domain, callback)) { | |
391 return; | |
392 } | |
393 } | |
394 } | |
395 callback.Run(base::File::FILE_ERROR_NOT_FOUND); | |
396 } | |
397 | |
398 void FileSystemContext::DeleteFileSystem( | |
399 const GURL& origin_url, | |
400 FileSystemType type, | |
401 const StatusCallback& callback) { | |
402 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
403 DCHECK(origin_url == origin_url.GetOrigin()); | |
404 DCHECK(!callback.is_null()); | |
405 | |
406 FileSystemBackend* backend = GetFileSystemBackend(type); | |
407 if (!backend) { | |
408 callback.Run(base::File::FILE_ERROR_SECURITY); | |
409 return; | |
410 } | |
411 if (!backend->GetQuotaUtil()) { | |
412 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); | |
413 return; | |
414 } | |
415 | |
416 base::PostTaskAndReplyWithResult( | |
417 default_file_task_runner(), | |
418 FROM_HERE, | |
419 // It is safe to pass Unretained(quota_util) since context owns it. | |
420 base::Bind(&FileSystemQuotaUtil::DeleteOriginDataOnFileTaskRunner, | |
421 base::Unretained(backend->GetQuotaUtil()), | |
422 make_scoped_refptr(this), | |
423 base::Unretained(quota_manager_proxy()), | |
424 origin_url, | |
425 type), | |
426 callback); | |
427 } | |
428 | |
429 scoped_ptr<storage::FileStreamReader> FileSystemContext::CreateFileStreamReader( | |
430 const FileSystemURL& url, | |
431 int64 offset, | |
432 const base::Time& expected_modification_time) { | |
433 if (!url.is_valid()) | |
434 return scoped_ptr<storage::FileStreamReader>(); | |
435 FileSystemBackend* backend = GetFileSystemBackend(url.type()); | |
436 if (!backend) | |
437 return scoped_ptr<storage::FileStreamReader>(); | |
438 return backend->CreateFileStreamReader( | |
439 url, offset, expected_modification_time, this); | |
440 } | |
441 | |
442 scoped_ptr<FileStreamWriter> FileSystemContext::CreateFileStreamWriter( | |
443 const FileSystemURL& url, | |
444 int64 offset) { | |
445 if (!url.is_valid()) | |
446 return scoped_ptr<FileStreamWriter>(); | |
447 FileSystemBackend* backend = GetFileSystemBackend(url.type()); | |
448 if (!backend) | |
449 return scoped_ptr<FileStreamWriter>(); | |
450 return backend->CreateFileStreamWriter(url, offset, this); | |
451 } | |
452 | |
453 scoped_ptr<FileSystemOperationRunner> | |
454 FileSystemContext::CreateFileSystemOperationRunner() { | |
455 return make_scoped_ptr(new FileSystemOperationRunner(this)); | |
456 } | |
457 | |
458 FileSystemURL FileSystemContext::CrackURL(const GURL& url) const { | |
459 return CrackFileSystemURL(FileSystemURL(url)); | |
460 } | |
461 | |
462 FileSystemURL FileSystemContext::CreateCrackedFileSystemURL( | |
463 const GURL& origin, | |
464 FileSystemType type, | |
465 const base::FilePath& path) const { | |
466 return CrackFileSystemURL(FileSystemURL(origin, type, path)); | |
467 } | |
468 | |
469 #if defined(OS_CHROMEOS) | |
470 void FileSystemContext::EnableTemporaryFileSystemInIncognito() { | |
471 sandbox_backend_->set_enable_temporary_file_system_in_incognito(true); | |
472 } | |
473 #endif | |
474 | |
475 bool FileSystemContext::CanServeURLRequest(const FileSystemURL& url) const { | |
476 // We never support accessing files in isolated filesystems via an URL. | |
477 if (url.mount_type() == kFileSystemTypeIsolated) | |
478 return false; | |
479 #if defined(OS_CHROMEOS) | |
480 if (url.type() == kFileSystemTypeTemporary && | |
481 sandbox_backend_->enable_temporary_file_system_in_incognito()) { | |
482 return true; | |
483 } | |
484 #endif | |
485 return !is_incognito_ || !FileSystemContext::IsSandboxFileSystem(url.type()); | |
486 } | |
487 | |
488 bool FileSystemContext::ShouldFlushOnWriteCompletion( | |
489 FileSystemType type) const { | |
490 if (IsSandboxFileSystem(type)) { | |
491 // Disable Flush() for each write operation on SandboxFileSystems since it | |
492 // hurts the performance, assuming the FileSystems are stored in a local | |
493 // disk, we don't need to keep calling fsync() for it. | |
494 // On the other hand, other FileSystems that may stored on a removable media | |
495 // should be Flush()ed as soon as a write operation is completed, so that | |
496 // written data is saved over sudden media removal. | |
497 return false; | |
498 } | |
499 return true; | |
500 } | |
501 | |
502 void FileSystemContext::OpenPluginPrivateFileSystem( | |
503 const GURL& origin_url, | |
504 FileSystemType type, | |
505 const std::string& filesystem_id, | |
506 const std::string& plugin_id, | |
507 OpenFileSystemMode mode, | |
508 const StatusCallback& callback) { | |
509 DCHECK(plugin_private_backend_); | |
510 plugin_private_backend_->OpenPrivateFileSystem( | |
511 origin_url, type, filesystem_id, plugin_id, mode, callback); | |
512 } | |
513 | |
514 FileSystemContext::~FileSystemContext() { | |
515 } | |
516 | |
517 void FileSystemContext::DeleteOnCorrectThread() const { | |
518 if (!io_task_runner_->RunsTasksOnCurrentThread() && | |
519 io_task_runner_->DeleteSoon(FROM_HERE, this)) { | |
520 return; | |
521 } | |
522 delete this; | |
523 } | |
524 | |
525 FileSystemOperation* FileSystemContext::CreateFileSystemOperation( | |
526 const FileSystemURL& url, base::File::Error* error_code) { | |
527 if (!url.is_valid()) { | |
528 if (error_code) | |
529 *error_code = base::File::FILE_ERROR_INVALID_URL; | |
530 return NULL; | |
531 } | |
532 | |
533 FileSystemBackend* backend = GetFileSystemBackend(url.type()); | |
534 if (!backend) { | |
535 if (error_code) | |
536 *error_code = base::File::FILE_ERROR_FAILED; | |
537 return NULL; | |
538 } | |
539 | |
540 base::File::Error fs_error = base::File::FILE_OK; | |
541 FileSystemOperation* operation = | |
542 backend->CreateFileSystemOperation(url, this, &fs_error); | |
543 | |
544 if (error_code) | |
545 *error_code = fs_error; | |
546 return operation; | |
547 } | |
548 | |
549 FileSystemURL FileSystemContext::CrackFileSystemURL( | |
550 const FileSystemURL& url) const { | |
551 if (!url.is_valid()) | |
552 return FileSystemURL(); | |
553 | |
554 // The returned value in case there is no crackers which can crack the url. | |
555 // This is valid situation for non isolated/external file systems. | |
556 FileSystemURL current = url; | |
557 | |
558 // File system may be mounted multiple times (e.g., an isolated filesystem on | |
559 // top of an external filesystem). Hence cracking needs to be iterated. | |
560 for (;;) { | |
561 FileSystemURL cracked = current; | |
562 for (size_t i = 0; i < url_crackers_.size(); ++i) { | |
563 if (!url_crackers_[i]->HandlesFileSystemMountType(current.type())) | |
564 continue; | |
565 cracked = url_crackers_[i]->CrackFileSystemURL(current); | |
566 if (cracked.is_valid()) | |
567 break; | |
568 } | |
569 if (cracked == current) | |
570 break; | |
571 current = cracked; | |
572 } | |
573 return current; | |
574 } | |
575 | |
576 void FileSystemContext::RegisterBackend(FileSystemBackend* backend) { | |
577 const FileSystemType mount_types[] = { | |
578 kFileSystemTypeTemporary, | |
579 kFileSystemTypePersistent, | |
580 kFileSystemTypeIsolated, | |
581 kFileSystemTypeExternal, | |
582 }; | |
583 // Register file system backends for public mount types. | |
584 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(mount_types); ++j) { | |
585 if (backend->CanHandleType(mount_types[j])) { | |
586 const bool inserted = backend_map_.insert( | |
587 std::make_pair(mount_types[j], backend)).second; | |
588 DCHECK(inserted); | |
589 } | |
590 } | |
591 // Register file system backends for internal types. | |
592 for (int t = kFileSystemInternalTypeEnumStart + 1; | |
593 t < kFileSystemInternalTypeEnumEnd; ++t) { | |
594 FileSystemType type = static_cast<FileSystemType>(t); | |
595 if (backend->CanHandleType(type)) { | |
596 const bool inserted = backend_map_.insert( | |
597 std::make_pair(type, backend)).second; | |
598 DCHECK(inserted); | |
599 } | |
600 } | |
601 } | |
602 | |
603 void FileSystemContext::DidOpenFileSystemForResolveURL( | |
604 const FileSystemURL& url, | |
605 const FileSystemContext::ResolveURLCallback& callback, | |
606 const GURL& filesystem_root, | |
607 const std::string& filesystem_name, | |
608 base::File::Error error) { | |
609 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
610 | |
611 if (error != base::File::FILE_OK) { | |
612 callback.Run(error, FileSystemInfo(), base::FilePath(), | |
613 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND); | |
614 return; | |
615 } | |
616 | |
617 storage::FileSystemInfo info( | |
618 filesystem_name, filesystem_root, url.mount_type()); | |
619 | |
620 // Extract the virtual path not containing a filesystem type part from |url|. | |
621 base::FilePath parent = CrackURL(filesystem_root).virtual_path(); | |
622 base::FilePath child = url.virtual_path(); | |
623 base::FilePath path; | |
624 | |
625 if (parent.empty()) { | |
626 path = child; | |
627 } else if (parent != child) { | |
628 bool result = parent.AppendRelativePath(child, &path); | |
629 DCHECK(result); | |
630 } | |
631 | |
632 operation_runner()->GetMetadata( | |
633 url, base::Bind(&DidGetMetadataForResolveURL, path, callback, info)); | |
634 } | |
635 | |
636 } // namespace storage | |
OLD | NEW |