summaryrefslogtreecommitdiff
path: root/chromium/webkit/browser/fileapi/isolated_context.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/webkit/browser/fileapi/isolated_context.cc')
-rw-r--r--chromium/webkit/browser/fileapi/isolated_context.cc469
1 files changed, 469 insertions, 0 deletions
diff --git a/chromium/webkit/browser/fileapi/isolated_context.cc b/chromium/webkit/browser/fileapi/isolated_context.cc
new file mode 100644
index 00000000000..d10438aa046
--- /dev/null
+++ b/chromium/webkit/browser/fileapi/isolated_context.cc
@@ -0,0 +1,469 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "webkit/browser/fileapi/isolated_context.h"
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+
+namespace fileapi {
+
+namespace {
+
+base::FilePath::StringType GetRegisterNameForPath(const base::FilePath& path) {
+ // If it's not a root path simply return a base name.
+ if (path.DirName() != path)
+ return path.BaseName().value();
+
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+ base::FilePath::StringType name;
+ for (size_t i = 0;
+ i < path.value().size() && !base::FilePath::IsSeparator(path.value()[i]);
+ ++i) {
+ if (path.value()[i] == L':') {
+ name.append(L"_drive");
+ break;
+ }
+ name.append(1, path.value()[i]);
+ }
+ return name;
+#else
+ return FILE_PATH_LITERAL("<root>");
+#endif
+}
+
+bool IsSinglePathIsolatedFileSystem(FileSystemType type) {
+ switch (type) {
+ // As of writing dragged file system is the only filesystem
+ // which could have multiple top-level paths.
+ case kFileSystemTypeDragged:
+ return false;
+
+ case kFileSystemTypeUnknown:
+ NOTREACHED();
+ return true;
+
+ default:
+ return true;
+ }
+ NOTREACHED();
+ return true;
+}
+
+static base::LazyInstance<IsolatedContext>::Leaky g_isolated_context =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+IsolatedContext::FileInfoSet::FileInfoSet() {}
+IsolatedContext::FileInfoSet::~FileInfoSet() {}
+
+bool IsolatedContext::FileInfoSet::AddPath(
+ const base::FilePath& path, std::string* registered_name) {
+ // The given path should not contain any '..' and should be absolute.
+ if (path.ReferencesParent() || !path.IsAbsolute())
+ return false;
+ base::FilePath::StringType name = GetRegisterNameForPath(path);
+ std::string utf8name = base::FilePath(name).AsUTF8Unsafe();
+ base::FilePath normalized_path = path.NormalizePathSeparators();
+ bool inserted =
+ fileset_.insert(MountPointInfo(utf8name, normalized_path)).second;
+ if (!inserted) {
+ int suffix = 1;
+ std::string basepart = base::FilePath(name).RemoveExtension().AsUTF8Unsafe();
+ std::string ext = base::FilePath(base::FilePath(name).Extension()).AsUTF8Unsafe();
+ while (!inserted) {
+ utf8name = base::StringPrintf("%s (%d)", basepart.c_str(), suffix++);
+ if (!ext.empty())
+ utf8name.append(ext);
+ inserted =
+ fileset_.insert(MountPointInfo(utf8name, normalized_path)).second;
+ }
+ }
+ if (registered_name)
+ *registered_name = utf8name;
+ return true;
+}
+
+bool IsolatedContext::FileInfoSet::AddPathWithName(
+ const base::FilePath& path, const std::string& name) {
+ // The given path should not contain any '..' and should be absolute.
+ if (path.ReferencesParent() || !path.IsAbsolute())
+ return false;
+ return fileset_.insert(
+ MountPointInfo(name, path.NormalizePathSeparators())).second;
+}
+
+//--------------------------------------------------------------------------
+
+class IsolatedContext::Instance {
+ public:
+ enum PathType {
+ PLATFORM_PATH,
+ VIRTUAL_PATH
+ };
+
+ // For a single-path isolated file system, which could be registered by
+ // IsolatedContext::RegisterFileSystemForPath() or
+ // IsolatedContext::RegisterFileSystemForVirtualPath().
+ // Most of isolated file system contexts should be of this type.
+ Instance(FileSystemType type, const MountPointInfo& file_info,
+ PathType path_type);
+
+ // For a multi-paths isolated file system. As of writing only file system
+ // type which could have multi-paths is Dragged file system, and
+ // could be registered by IsolatedContext::RegisterDraggedFileSystem().
+ Instance(FileSystemType type, const std::set<MountPointInfo>& files);
+
+ ~Instance();
+
+ FileSystemType type() const { return type_; }
+ const MountPointInfo& file_info() const { return file_info_; }
+ const std::set<MountPointInfo>& files() const { return files_; }
+ int ref_counts() const { return ref_counts_; }
+
+ void AddRef() { ++ref_counts_; }
+ void RemoveRef() { --ref_counts_; }
+
+ bool ResolvePathForName(const std::string& name, base::FilePath* path) const;
+
+ // Returns true if the instance is a single-path instance.
+ bool IsSinglePathInstance() const;
+
+ private:
+ const FileSystemType type_;
+
+ // For single-path instance.
+ const MountPointInfo file_info_;
+ const PathType path_type_;
+
+ // For multiple-path instance (e.g. dragged file system).
+ const std::set<MountPointInfo> files_;
+
+ // Reference counts. Note that an isolated filesystem is created with ref==0
+ // and will get deleted when the ref count reaches <=0.
+ int ref_counts_;
+
+ DISALLOW_COPY_AND_ASSIGN(Instance);
+};
+
+IsolatedContext::Instance::Instance(FileSystemType type,
+ const MountPointInfo& file_info,
+ Instance::PathType path_type)
+ : type_(type),
+ file_info_(file_info),
+ path_type_(path_type),
+ ref_counts_(0) {
+ DCHECK(IsSinglePathIsolatedFileSystem(type_));
+}
+
+IsolatedContext::Instance::Instance(FileSystemType type,
+ const std::set<MountPointInfo>& files)
+ : type_(type),
+ path_type_(PLATFORM_PATH),
+ files_(files),
+ ref_counts_(0) {
+ DCHECK(!IsSinglePathIsolatedFileSystem(type_));
+}
+
+IsolatedContext::Instance::~Instance() {}
+
+bool IsolatedContext::Instance::ResolvePathForName(const std::string& name,
+ base::FilePath* path) const {
+ if (IsSinglePathIsolatedFileSystem(type_)) {
+ switch (path_type_) {
+ case PLATFORM_PATH:
+ *path = file_info_.path;
+ break;
+ case VIRTUAL_PATH:
+ *path = base::FilePath();
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ return file_info_.name == name;
+ }
+ std::set<MountPointInfo>::const_iterator found = files_.find(
+ MountPointInfo(name, base::FilePath()));
+ if (found == files_.end())
+ return false;
+ *path = found->path;
+ return true;
+}
+
+bool IsolatedContext::Instance::IsSinglePathInstance() const {
+ return IsSinglePathIsolatedFileSystem(type_);
+}
+
+//--------------------------------------------------------------------------
+
+// static
+IsolatedContext* IsolatedContext::GetInstance() {
+ return g_isolated_context.Pointer();
+}
+
+// static
+bool IsolatedContext::IsIsolatedType(FileSystemType type) {
+ return type == kFileSystemTypeIsolated || type == kFileSystemTypeExternal;
+}
+
+std::string IsolatedContext::RegisterDraggedFileSystem(
+ const FileInfoSet& files) {
+ base::AutoLock locker(lock_);
+ std::string filesystem_id = GetNewFileSystemId();
+ instance_map_[filesystem_id] = new Instance(
+ kFileSystemTypeDragged, files.fileset());
+ return filesystem_id;
+}
+
+std::string IsolatedContext::RegisterFileSystemForPath(
+ FileSystemType type,
+ const base::FilePath& path_in,
+ std::string* register_name) {
+ base::FilePath path(path_in.NormalizePathSeparators());
+ if (path.ReferencesParent() || !path.IsAbsolute())
+ return std::string();
+ std::string name;
+ if (register_name && !register_name->empty()) {
+ name = *register_name;
+ } else {
+ name = base::FilePath(GetRegisterNameForPath(path)).AsUTF8Unsafe();
+ if (register_name)
+ register_name->assign(name);
+ }
+
+ base::AutoLock locker(lock_);
+ std::string filesystem_id = GetNewFileSystemId();
+ instance_map_[filesystem_id] = new Instance(type, MountPointInfo(name, path),
+ Instance::PLATFORM_PATH);
+ path_to_id_map_[path].insert(filesystem_id);
+ return filesystem_id;
+}
+
+std::string IsolatedContext::RegisterFileSystemForVirtualPath(
+ FileSystemType type,
+ const std::string& register_name,
+ const base::FilePath& cracked_path_prefix) {
+ base::AutoLock locker(lock_);
+ base::FilePath path(cracked_path_prefix.NormalizePathSeparators());
+ if (path.ReferencesParent())
+ return std::string();
+ std::string filesystem_id = GetNewFileSystemId();
+ instance_map_[filesystem_id] = new Instance(
+ type,
+ MountPointInfo(register_name, cracked_path_prefix),
+ Instance::VIRTUAL_PATH);
+ path_to_id_map_[path].insert(filesystem_id);
+ return filesystem_id;
+}
+
+bool IsolatedContext::HandlesFileSystemMountType(FileSystemType type) const {
+ return type == kFileSystemTypeIsolated;
+}
+
+bool IsolatedContext::RevokeFileSystem(const std::string& filesystem_id) {
+ base::AutoLock locker(lock_);
+ return UnregisterFileSystem(filesystem_id);
+}
+
+bool IsolatedContext::GetRegisteredPath(
+ const std::string& filesystem_id, base::FilePath* path) const {
+ DCHECK(path);
+ base::AutoLock locker(lock_);
+ IDToInstance::const_iterator found = instance_map_.find(filesystem_id);
+ if (found == instance_map_.end() || !found->second->IsSinglePathInstance())
+ return false;
+ *path = found->second->file_info().path;
+ return true;
+}
+
+bool IsolatedContext::CrackVirtualPath(const base::FilePath& virtual_path,
+ std::string* id_or_name,
+ FileSystemType* type,
+ base::FilePath* path) const {
+ DCHECK(id_or_name);
+ DCHECK(path);
+
+ // This should not contain any '..' references.
+ if (virtual_path.ReferencesParent())
+ return false;
+
+ // The virtual_path should comprise <id_or_name> and <relative_path> parts.
+ std::vector<base::FilePath::StringType> components;
+ virtual_path.GetComponents(&components);
+ if (components.size() < 1)
+ return false;
+ std::vector<base::FilePath::StringType>::iterator component_iter =
+ components.begin();
+ std::string fsid = base::FilePath(*component_iter++).MaybeAsASCII();
+ if (fsid.empty())
+ return false;
+
+ base::FilePath cracked_path;
+ {
+ base::AutoLock locker(lock_);
+ IDToInstance::const_iterator found_instance = instance_map_.find(fsid);
+ if (found_instance == instance_map_.end())
+ return false;
+ *id_or_name = fsid;
+ const Instance* instance = found_instance->second;
+ if (type)
+ *type = instance->type();
+
+ if (component_iter == components.end()) {
+ // The virtual root case.
+ path->clear();
+ return true;
+ }
+
+ // *component_iter should be a name of the registered path.
+ std::string name = base::FilePath(*component_iter++).AsUTF8Unsafe();
+ if (!instance->ResolvePathForName(name, &cracked_path))
+ return false;
+ }
+
+ for (; component_iter != components.end(); ++component_iter)
+ cracked_path = cracked_path.Append(*component_iter);
+ *path = cracked_path;
+ return true;
+}
+
+FileSystemURL IsolatedContext::CrackURL(const GURL& url) const {
+ FileSystemURL filesystem_url = FileSystemURL(url);
+ if (!filesystem_url.is_valid())
+ return FileSystemURL();
+ return CrackFileSystemURL(filesystem_url);
+}
+
+FileSystemURL IsolatedContext::CreateCrackedFileSystemURL(
+ const GURL& origin,
+ FileSystemType type,
+ const base::FilePath& path) const {
+ return CrackFileSystemURL(FileSystemURL(origin, type, path));
+}
+
+void IsolatedContext::RevokeFileSystemByPath(const base::FilePath& path_in) {
+ base::AutoLock locker(lock_);
+ base::FilePath path(path_in.NormalizePathSeparators());
+ PathToID::iterator ids_iter = path_to_id_map_.find(path);
+ if (ids_iter == path_to_id_map_.end())
+ return;
+ std::set<std::string>& ids = ids_iter->second;
+ for (std::set<std::string>::iterator iter = ids.begin();
+ iter != ids.end(); ++iter) {
+ IDToInstance::iterator found = instance_map_.find(*iter);
+ if (found != instance_map_.end()) {
+ delete found->second;
+ instance_map_.erase(found);
+ }
+ }
+ path_to_id_map_.erase(ids_iter);
+}
+
+void IsolatedContext::AddReference(const std::string& filesystem_id) {
+ base::AutoLock locker(lock_);
+ DCHECK(instance_map_.find(filesystem_id) != instance_map_.end());
+ instance_map_[filesystem_id]->AddRef();
+}
+
+void IsolatedContext::RemoveReference(const std::string& filesystem_id) {
+ base::AutoLock locker(lock_);
+ // This could get called for non-existent filesystem if it has been
+ // already deleted by RevokeFileSystemByPath.
+ IDToInstance::iterator found = instance_map_.find(filesystem_id);
+ if (found == instance_map_.end())
+ return;
+ Instance* instance = found->second;
+ DCHECK_GT(instance->ref_counts(), 0);
+ instance->RemoveRef();
+ if (instance->ref_counts() == 0) {
+ bool deleted = UnregisterFileSystem(filesystem_id);
+ DCHECK(deleted);
+ }
+}
+
+bool IsolatedContext::GetDraggedFileInfo(
+ const std::string& filesystem_id,
+ std::vector<MountPointInfo>* files) const {
+ DCHECK(files);
+ base::AutoLock locker(lock_);
+ IDToInstance::const_iterator found = instance_map_.find(filesystem_id);
+ if (found == instance_map_.end() ||
+ found->second->type() != kFileSystemTypeDragged)
+ return false;
+ files->assign(found->second->files().begin(),
+ found->second->files().end());
+ return true;
+}
+
+base::FilePath IsolatedContext::CreateVirtualRootPath(
+ const std::string& filesystem_id) const {
+ return base::FilePath().AppendASCII(filesystem_id);
+}
+
+IsolatedContext::IsolatedContext() {
+}
+
+IsolatedContext::~IsolatedContext() {
+ STLDeleteContainerPairSecondPointers(instance_map_.begin(),
+ instance_map_.end());
+}
+
+FileSystemURL IsolatedContext::CrackFileSystemURL(
+ const FileSystemURL& url) const {
+ if (!HandlesFileSystemMountType(url.type()))
+ return FileSystemURL();
+
+ std::string mount_name;
+ FileSystemType cracked_type;
+ base::FilePath cracked_path;
+ if (!CrackVirtualPath(url.path(), &mount_name, &cracked_type, &cracked_path))
+ return FileSystemURL();
+
+ return FileSystemURL(
+ url.origin(), url.mount_type(), url.virtual_path(),
+ !url.filesystem_id().empty() ? url.filesystem_id() : mount_name,
+ cracked_type, cracked_path, mount_name);
+}
+
+bool IsolatedContext::UnregisterFileSystem(const std::string& filesystem_id) {
+ lock_.AssertAcquired();
+ IDToInstance::iterator found = instance_map_.find(filesystem_id);
+ if (found == instance_map_.end())
+ return false;
+ Instance* instance = found->second;
+ if (instance->IsSinglePathInstance()) {
+ PathToID::iterator ids_iter = path_to_id_map_.find(
+ instance->file_info().path);
+ DCHECK(ids_iter != path_to_id_map_.end());
+ ids_iter->second.erase(filesystem_id);
+ if (ids_iter->second.empty())
+ path_to_id_map_.erase(ids_iter);
+ }
+ delete found->second;
+ instance_map_.erase(found);
+ return true;
+}
+
+std::string IsolatedContext::GetNewFileSystemId() const {
+ // Returns an arbitrary random string which must be unique in the map.
+ lock_.AssertAcquired();
+ uint32 random_data[4];
+ std::string id;
+ do {
+ base::RandBytes(random_data, sizeof(random_data));
+ id = base::HexEncode(random_data, sizeof(random_data));
+ } while (instance_map_.find(id) != instance_map_.end());
+ return id;
+}
+
+} // namespace fileapi