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 quota::QuotaClient; | |
35 | |
36 namespace fileapi { | |
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 quota::SpecialStoragePolicy* special_storage_policy, | |
138 quota::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_(new SandboxFileSystemBackendDelegate( | |
147 quota_manager_proxy, | |
148 file_task_runner, | |
149 partition_path, | |
150 special_storage_policy, | |
151 options)), | |
152 sandbox_backend_(new SandboxFileSystemBackend( | |
153 sandbox_delegate_.get())), | |
154 isolated_backend_(new IsolatedFileSystemBackend()), | |
155 plugin_private_backend_(new PluginPrivateFileSystemBackend( | |
156 file_task_runner, | |
157 partition_path, | |
158 special_storage_policy, | |
159 options)), | |
160 additional_backends_(additional_backends.Pass()), | |
161 auto_mount_handlers_(auto_mount_handlers), | |
162 external_mount_points_(external_mount_points), | |
163 partition_path_(partition_path), | |
164 is_incognito_(options.is_incognito()), | |
165 operation_runner_(new FileSystemOperationRunner(this)) { | |
166 RegisterBackend(sandbox_backend_.get()); | |
167 RegisterBackend(isolated_backend_.get()); | |
168 RegisterBackend(plugin_private_backend_.get()); | |
169 | |
170 for (ScopedVector<FileSystemBackend>::const_iterator iter = | |
171 additional_backends_.begin(); | |
172 iter != additional_backends_.end(); ++iter) { | |
173 RegisterBackend(*iter); | |
174 } | |
175 | |
176 if (quota_manager_proxy) { | |
177 // Quota client assumes all backends have registered. | |
178 quota_manager_proxy->RegisterClient(CreateQuotaClient( | |
179 this, options.is_incognito())); | |
180 } | |
181 | |
182 sandbox_backend_->Initialize(this); | |
183 isolated_backend_->Initialize(this); | |
184 plugin_private_backend_->Initialize(this); | |
185 for (ScopedVector<FileSystemBackend>::const_iterator iter = | |
186 additional_backends_.begin(); | |
187 iter != additional_backends_.end(); ++iter) { | |
188 (*iter)->Initialize(this); | |
189 } | |
190 | |
191 // Additional mount points must be added before regular system-wide | |
192 // mount points. | |
193 if (external_mount_points) | |
194 url_crackers_.push_back(external_mount_points); | |
195 url_crackers_.push_back(ExternalMountPoints::GetSystemInstance()); | |
196 url_crackers_.push_back(IsolatedContext::GetInstance()); | |
197 } | |
198 | |
199 bool FileSystemContext::DeleteDataForOriginOnFileTaskRunner( | |
200 const GURL& origin_url) { | |
201 DCHECK(default_file_task_runner()->RunsTasksOnCurrentThread()); | |
202 DCHECK(origin_url == origin_url.GetOrigin()); | |
203 | |
204 bool success = true; | |
205 for (FileSystemBackendMap::iterator iter = backend_map_.begin(); | |
206 iter != backend_map_.end(); | |
207 ++iter) { | |
208 FileSystemBackend* backend = iter->second; | |
209 if (!backend->GetQuotaUtil()) | |
210 continue; | |
211 if (backend->GetQuotaUtil()->DeleteOriginDataOnFileTaskRunner( | |
212 this, quota_manager_proxy(), origin_url, iter->first) | |
213 != base::File::FILE_OK) { | |
214 // Continue the loop, but record the failure. | |
215 success = false; | |
216 } | |
217 } | |
218 | |
219 return success; | |
220 } | |
221 | |
222 scoped_refptr<QuotaReservation> | |
223 FileSystemContext::CreateQuotaReservationOnFileTaskRunner( | |
224 const GURL& origin_url, | |
225 FileSystemType type) { | |
226 DCHECK(default_file_task_runner()->RunsTasksOnCurrentThread()); | |
227 FileSystemBackend* backend = GetFileSystemBackend(type); | |
228 if (!backend || !backend->GetQuotaUtil()) | |
229 return scoped_refptr<QuotaReservation>(); | |
230 return backend->GetQuotaUtil()->CreateQuotaReservationOnFileTaskRunner( | |
231 origin_url, type); | |
232 } | |
233 | |
234 void FileSystemContext::Shutdown() { | |
235 if (!io_task_runner_->RunsTasksOnCurrentThread()) { | |
236 io_task_runner_->PostTask( | |
237 FROM_HERE, base::Bind(&FileSystemContext::Shutdown, | |
238 make_scoped_refptr(this))); | |
239 return; | |
240 } | |
241 operation_runner_->Shutdown(); | |
242 } | |
243 | |
244 FileSystemQuotaUtil* | |
245 FileSystemContext::GetQuotaUtil(FileSystemType type) const { | |
246 FileSystemBackend* backend = GetFileSystemBackend(type); | |
247 if (!backend) | |
248 return NULL; | |
249 return backend->GetQuotaUtil(); | |
250 } | |
251 | |
252 AsyncFileUtil* FileSystemContext::GetAsyncFileUtil( | |
253 FileSystemType type) const { | |
254 FileSystemBackend* backend = GetFileSystemBackend(type); | |
255 if (!backend) | |
256 return NULL; | |
257 return backend->GetAsyncFileUtil(type); | |
258 } | |
259 | |
260 CopyOrMoveFileValidatorFactory* | |
261 FileSystemContext::GetCopyOrMoveFileValidatorFactory( | |
262 FileSystemType type, base::File::Error* error_code) const { | |
263 DCHECK(error_code); | |
264 *error_code = base::File::FILE_OK; | |
265 FileSystemBackend* backend = GetFileSystemBackend(type); | |
266 if (!backend) | |
267 return NULL; | |
268 return backend->GetCopyOrMoveFileValidatorFactory( | |
269 type, error_code); | |
270 } | |
271 | |
272 FileSystemBackend* FileSystemContext::GetFileSystemBackend( | |
273 FileSystemType type) const { | |
274 FileSystemBackendMap::const_iterator found = backend_map_.find(type); | |
275 if (found != backend_map_.end()) | |
276 return found->second; | |
277 NOTREACHED() << "Unknown filesystem type: " << type; | |
278 return NULL; | |
279 } | |
280 | |
281 bool FileSystemContext::IsSandboxFileSystem(FileSystemType type) const { | |
282 FileSystemBackendMap::const_iterator found = backend_map_.find(type); | |
283 return found != backend_map_.end() && found->second->GetQuotaUtil(); | |
284 } | |
285 | |
286 const UpdateObserverList* FileSystemContext::GetUpdateObservers( | |
287 FileSystemType type) const { | |
288 FileSystemBackend* backend = GetFileSystemBackend(type); | |
289 if (backend->GetQuotaUtil()) | |
290 return backend->GetQuotaUtil()->GetUpdateObservers(type); | |
291 return NULL; | |
292 } | |
293 | |
294 const AccessObserverList* FileSystemContext::GetAccessObservers( | |
295 FileSystemType type) const { | |
296 FileSystemBackend* backend = GetFileSystemBackend(type); | |
297 if (backend->GetQuotaUtil()) | |
298 return backend->GetQuotaUtil()->GetAccessObservers(type); | |
299 return NULL; | |
300 } | |
301 | |
302 void FileSystemContext::GetFileSystemTypes( | |
303 std::vector<FileSystemType>* types) const { | |
304 types->clear(); | |
305 for (FileSystemBackendMap::const_iterator iter = backend_map_.begin(); | |
306 iter != backend_map_.end(); ++iter) | |
307 types->push_back(iter->first); | |
308 } | |
309 | |
310 ExternalFileSystemBackend* | |
311 FileSystemContext::external_backend() const { | |
312 return static_cast<ExternalFileSystemBackend*>( | |
313 GetFileSystemBackend(kFileSystemTypeExternal)); | |
314 } | |
315 | |
316 void FileSystemContext::OpenFileSystem( | |
317 const GURL& origin_url, | |
318 FileSystemType type, | |
319 OpenFileSystemMode mode, | |
320 const OpenFileSystemCallback& callback) { | |
321 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
322 DCHECK(!callback.is_null()); | |
323 | |
324 if (!FileSystemContext::IsSandboxFileSystem(type)) { | |
325 // Disallow opening a non-sandboxed filesystem. | |
326 callback.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY); | |
327 return; | |
328 } | |
329 | |
330 FileSystemBackend* backend = GetFileSystemBackend(type); | |
331 if (!backend) { | |
332 callback.Run(GURL(), std::string(), base::File::FILE_ERROR_SECURITY); | |
333 return; | |
334 } | |
335 | |
336 backend->ResolveURL( | |
337 CreateCrackedFileSystemURL(origin_url, type, base::FilePath()), | |
338 mode, | |
339 callback); | |
340 } | |
341 | |
342 void FileSystemContext::ResolveURL( | |
343 const FileSystemURL& url, | |
344 const ResolveURLCallback& callback) { | |
345 DCHECK(!callback.is_null()); | |
346 | |
347 // If not on IO thread, forward before passing the task to the backend. | |
348 if (!io_task_runner_->RunsTasksOnCurrentThread()) { | |
349 ResolveURLCallback relay_callback = | |
350 base::Bind(&RelayResolveURLCallback, | |
351 base::MessageLoopProxy::current(), callback); | |
352 io_task_runner_->PostTask( | |
353 FROM_HERE, | |
354 base::Bind(&FileSystemContext::ResolveURL, this, url, relay_callback)); | |
355 return; | |
356 } | |
357 | |
358 FileSystemBackend* backend = GetFileSystemBackend(url.type()); | |
359 if (!backend) { | |
360 callback.Run(base::File::FILE_ERROR_SECURITY, | |
361 FileSystemInfo(), base::FilePath(), | |
362 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND); | |
363 return; | |
364 } | |
365 | |
366 backend->ResolveURL( | |
367 url, | |
368 OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT, | |
369 base::Bind(&FileSystemContext::DidOpenFileSystemForResolveURL, | |
370 this, | |
371 url, | |
372 callback)); | |
373 } | |
374 | |
375 void FileSystemContext::AttemptAutoMountForURLRequest( | |
376 const net::URLRequest* url_request, | |
377 const std::string& storage_domain, | |
378 const StatusCallback& callback) { | |
379 FileSystemURL filesystem_url(url_request->url()); | |
380 if (filesystem_url.type() == kFileSystemTypeExternal) { | |
381 for (size_t i = 0; i < auto_mount_handlers_.size(); i++) { | |
382 if (auto_mount_handlers_[i].Run(url_request, filesystem_url, | |
383 storage_domain, callback)) { | |
384 return; | |
385 } | |
386 } | |
387 } | |
388 callback.Run(base::File::FILE_ERROR_NOT_FOUND); | |
389 } | |
390 | |
391 void FileSystemContext::DeleteFileSystem( | |
392 const GURL& origin_url, | |
393 FileSystemType type, | |
394 const StatusCallback& callback) { | |
395 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
396 DCHECK(origin_url == origin_url.GetOrigin()); | |
397 DCHECK(!callback.is_null()); | |
398 | |
399 FileSystemBackend* backend = GetFileSystemBackend(type); | |
400 if (!backend) { | |
401 callback.Run(base::File::FILE_ERROR_SECURITY); | |
402 return; | |
403 } | |
404 if (!backend->GetQuotaUtil()) { | |
405 callback.Run(base::File::FILE_ERROR_INVALID_OPERATION); | |
406 return; | |
407 } | |
408 | |
409 base::PostTaskAndReplyWithResult( | |
410 default_file_task_runner(), | |
411 FROM_HERE, | |
412 // It is safe to pass Unretained(quota_util) since context owns it. | |
413 base::Bind(&FileSystemQuotaUtil::DeleteOriginDataOnFileTaskRunner, | |
414 base::Unretained(backend->GetQuotaUtil()), | |
415 make_scoped_refptr(this), | |
416 base::Unretained(quota_manager_proxy()), | |
417 origin_url, | |
418 type), | |
419 callback); | |
420 } | |
421 | |
422 scoped_ptr<webkit_blob::FileStreamReader> | |
423 FileSystemContext::CreateFileStreamReader( | |
424 const FileSystemURL& url, | |
425 int64 offset, | |
426 const base::Time& expected_modification_time) { | |
427 if (!url.is_valid()) | |
428 return scoped_ptr<webkit_blob::FileStreamReader>(); | |
429 FileSystemBackend* backend = GetFileSystemBackend(url.type()); | |
430 if (!backend) | |
431 return scoped_ptr<webkit_blob::FileStreamReader>(); | |
432 return backend->CreateFileStreamReader( | |
433 url, offset, expected_modification_time, this); | |
434 } | |
435 | |
436 scoped_ptr<FileStreamWriter> FileSystemContext::CreateFileStreamWriter( | |
437 const FileSystemURL& url, | |
438 int64 offset) { | |
439 if (!url.is_valid()) | |
440 return scoped_ptr<FileStreamWriter>(); | |
441 FileSystemBackend* backend = GetFileSystemBackend(url.type()); | |
442 if (!backend) | |
443 return scoped_ptr<FileStreamWriter>(); | |
444 return backend->CreateFileStreamWriter(url, offset, this); | |
445 } | |
446 | |
447 scoped_ptr<FileSystemOperationRunner> | |
448 FileSystemContext::CreateFileSystemOperationRunner() { | |
449 return make_scoped_ptr(new FileSystemOperationRunner(this)); | |
450 } | |
451 | |
452 FileSystemURL FileSystemContext::CrackURL(const GURL& url) const { | |
453 return CrackFileSystemURL(FileSystemURL(url)); | |
454 } | |
455 | |
456 FileSystemURL FileSystemContext::CreateCrackedFileSystemURL( | |
457 const GURL& origin, | |
458 FileSystemType type, | |
459 const base::FilePath& path) const { | |
460 return CrackFileSystemURL(FileSystemURL(origin, type, path)); | |
461 } | |
462 | |
463 #if defined(OS_CHROMEOS) | |
464 void FileSystemContext::EnableTemporaryFileSystemInIncognito() { | |
465 sandbox_backend_->set_enable_temporary_file_system_in_incognito(true); | |
466 } | |
467 #endif | |
468 | |
469 bool FileSystemContext::CanServeURLRequest(const FileSystemURL& url) const { | |
470 // We never support accessing files in isolated filesystems via an URL. | |
471 if (url.mount_type() == kFileSystemTypeIsolated) | |
472 return false; | |
473 #if defined(OS_CHROMEOS) | |
474 if (url.type() == kFileSystemTypeTemporary && | |
475 sandbox_backend_->enable_temporary_file_system_in_incognito()) { | |
476 return true; | |
477 } | |
478 #endif | |
479 return !is_incognito_ || !FileSystemContext::IsSandboxFileSystem(url.type()); | |
480 } | |
481 | |
482 bool FileSystemContext::ShouldFlushOnWriteCompletion( | |
483 FileSystemType type) const { | |
484 if (IsSandboxFileSystem(type)) { | |
485 // Disable Flush() for each write operation on SandboxFileSystems since it | |
486 // hurts the performance, assuming the FileSystems are stored in a local | |
487 // disk, we don't need to keep calling fsync() for it. | |
488 // On the other hand, other FileSystems that may stored on a removable media | |
489 // should be Flush()ed as soon as a write operation is completed, so that | |
490 // written data is saved over sudden media removal. | |
491 return false; | |
492 } | |
493 return true; | |
494 } | |
495 | |
496 void FileSystemContext::OpenPluginPrivateFileSystem( | |
497 const GURL& origin_url, | |
498 FileSystemType type, | |
499 const std::string& filesystem_id, | |
500 const std::string& plugin_id, | |
501 OpenFileSystemMode mode, | |
502 const StatusCallback& callback) { | |
503 DCHECK(plugin_private_backend_); | |
504 plugin_private_backend_->OpenPrivateFileSystem( | |
505 origin_url, type, filesystem_id, plugin_id, mode, callback); | |
506 } | |
507 | |
508 FileSystemContext::~FileSystemContext() { | |
509 } | |
510 | |
511 void FileSystemContext::DeleteOnCorrectThread() const { | |
512 if (!io_task_runner_->RunsTasksOnCurrentThread() && | |
513 io_task_runner_->DeleteSoon(FROM_HERE, this)) { | |
514 return; | |
515 } | |
516 delete this; | |
517 } | |
518 | |
519 FileSystemOperation* FileSystemContext::CreateFileSystemOperation( | |
520 const FileSystemURL& url, base::File::Error* error_code) { | |
521 if (!url.is_valid()) { | |
522 if (error_code) | |
523 *error_code = base::File::FILE_ERROR_INVALID_URL; | |
524 return NULL; | |
525 } | |
526 | |
527 FileSystemBackend* backend = GetFileSystemBackend(url.type()); | |
528 if (!backend) { | |
529 if (error_code) | |
530 *error_code = base::File::FILE_ERROR_FAILED; | |
531 return NULL; | |
532 } | |
533 | |
534 base::File::Error fs_error = base::File::FILE_OK; | |
535 FileSystemOperation* operation = | |
536 backend->CreateFileSystemOperation(url, this, &fs_error); | |
537 | |
538 if (error_code) | |
539 *error_code = fs_error; | |
540 return operation; | |
541 } | |
542 | |
543 FileSystemURL FileSystemContext::CrackFileSystemURL( | |
544 const FileSystemURL& url) const { | |
545 if (!url.is_valid()) | |
546 return FileSystemURL(); | |
547 | |
548 // The returned value in case there is no crackers which can crack the url. | |
549 // This is valid situation for non isolated/external file systems. | |
550 FileSystemURL current = url; | |
551 | |
552 // File system may be mounted multiple times (e.g., an isolated filesystem on | |
553 // top of an external filesystem). Hence cracking needs to be iterated. | |
554 for (;;) { | |
555 FileSystemURL cracked = current; | |
556 for (size_t i = 0; i < url_crackers_.size(); ++i) { | |
557 if (!url_crackers_[i]->HandlesFileSystemMountType(current.type())) | |
558 continue; | |
559 cracked = url_crackers_[i]->CrackFileSystemURL(current); | |
560 if (cracked.is_valid()) | |
561 break; | |
562 } | |
563 if (cracked == current) | |
564 break; | |
565 current = cracked; | |
566 } | |
567 return current; | |
568 } | |
569 | |
570 void FileSystemContext::RegisterBackend(FileSystemBackend* backend) { | |
571 const FileSystemType mount_types[] = { | |
572 kFileSystemTypeTemporary, | |
573 kFileSystemTypePersistent, | |
574 kFileSystemTypeIsolated, | |
575 kFileSystemTypeExternal, | |
576 }; | |
577 // Register file system backends for public mount types. | |
578 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(mount_types); ++j) { | |
579 if (backend->CanHandleType(mount_types[j])) { | |
580 const bool inserted = backend_map_.insert( | |
581 std::make_pair(mount_types[j], backend)).second; | |
582 DCHECK(inserted); | |
583 } | |
584 } | |
585 // Register file system backends for internal types. | |
586 for (int t = kFileSystemInternalTypeEnumStart + 1; | |
587 t < kFileSystemInternalTypeEnumEnd; ++t) { | |
588 FileSystemType type = static_cast<FileSystemType>(t); | |
589 if (backend->CanHandleType(type)) { | |
590 const bool inserted = backend_map_.insert( | |
591 std::make_pair(type, backend)).second; | |
592 DCHECK(inserted); | |
593 } | |
594 } | |
595 } | |
596 | |
597 void FileSystemContext::DidOpenFileSystemForResolveURL( | |
598 const FileSystemURL& url, | |
599 const FileSystemContext::ResolveURLCallback& callback, | |
600 const GURL& filesystem_root, | |
601 const std::string& filesystem_name, | |
602 base::File::Error error) { | |
603 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); | |
604 | |
605 if (error != base::File::FILE_OK) { | |
606 callback.Run(error, FileSystemInfo(), base::FilePath(), | |
607 FileSystemContext::RESOLVED_ENTRY_NOT_FOUND); | |
608 return; | |
609 } | |
610 | |
611 fileapi::FileSystemInfo info( | |
612 filesystem_name, filesystem_root, url.mount_type()); | |
613 | |
614 // Extract the virtual path not containing a filesystem type part from |url|. | |
615 base::FilePath parent = CrackURL(filesystem_root).virtual_path(); | |
616 base::FilePath child = url.virtual_path(); | |
617 base::FilePath path; | |
618 | |
619 if (parent.empty()) { | |
620 path = child; | |
621 } else if (parent != child) { | |
622 bool result = parent.AppendRelativePath(child, &path); | |
623 DCHECK(result); | |
624 } | |
625 | |
626 operation_runner()->GetMetadata( | |
627 url, base::Bind(&DidGetMetadataForResolveURL, path, callback, info)); | |
628 } | |
629 | |
630 } // namespace fileapi | |
OLD | NEW |