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