We started redesigning GpuMemoryBuffer interface to handle multiple buffers [0].
[chromium-blink-merge.git] / storage / browser / fileapi / isolated_context.cc
blob20e28c1a16d6389dbb0f2dae87b37c39b43ccc18
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.
5 #include "storage/browser/fileapi/isolated_context.h"
7 #include "base/basictypes.h"
8 #include "base/files/file_path.h"
9 #include "base/logging.h"
10 #include "base/rand_util.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "storage/browser/fileapi/file_system_url.h"
17 namespace storage {
19 namespace {
21 base::FilePath::StringType GetRegisterNameForPath(const base::FilePath& path) {
22 // If it's not a root path simply return a base name.
23 if (path.DirName() != path)
24 return path.BaseName().value();
26 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
27 base::FilePath::StringType name;
28 for (size_t i = 0;
29 i < path.value().size() && !base::FilePath::IsSeparator(path.value()[i]);
30 ++i) {
31 if (path.value()[i] == L':') {
32 name.append(L"_drive");
33 break;
35 name.append(1, path.value()[i]);
37 return name;
38 #else
39 return FILE_PATH_LITERAL("<root>");
40 #endif
43 bool IsSinglePathIsolatedFileSystem(FileSystemType type) {
44 DCHECK_NE(kFileSystemTypeUnknown, type);
45 // As of writing dragged file system is the only filesystem which could have
46 // multiple top-level paths.
47 return type != kFileSystemTypeDragged;
50 static base::LazyInstance<IsolatedContext>::Leaky g_isolated_context =
51 LAZY_INSTANCE_INITIALIZER;
53 } // namespace
55 IsolatedContext::FileInfoSet::FileInfoSet() {}
56 IsolatedContext::FileInfoSet::~FileInfoSet() {}
58 bool IsolatedContext::FileInfoSet::AddPath(
59 const base::FilePath& path, std::string* registered_name) {
60 // The given path should not contain any '..' and should be absolute.
61 if (path.ReferencesParent() || !path.IsAbsolute())
62 return false;
63 base::FilePath::StringType name = GetRegisterNameForPath(path);
64 std::string utf8name = base::FilePath(name).AsUTF8Unsafe();
65 base::FilePath normalized_path = path.NormalizePathSeparators();
66 bool inserted =
67 fileset_.insert(MountPointInfo(utf8name, normalized_path)).second;
68 if (!inserted) {
69 int suffix = 1;
70 std::string basepart =
71 base::FilePath(name).RemoveExtension().AsUTF8Unsafe();
72 std::string ext =
73 base::FilePath(base::FilePath(name).Extension()).AsUTF8Unsafe();
74 while (!inserted) {
75 utf8name = base::StringPrintf("%s (%d)", basepart.c_str(), suffix++);
76 if (!ext.empty())
77 utf8name.append(ext);
78 inserted =
79 fileset_.insert(MountPointInfo(utf8name, normalized_path)).second;
82 if (registered_name)
83 *registered_name = utf8name;
84 return true;
87 bool IsolatedContext::FileInfoSet::AddPathWithName(
88 const base::FilePath& path, const std::string& name) {
89 // The given path should not contain any '..' and should be absolute.
90 if (path.ReferencesParent() || !path.IsAbsolute())
91 return false;
92 return fileset_.insert(
93 MountPointInfo(name, path.NormalizePathSeparators())).second;
96 //--------------------------------------------------------------------------
98 class IsolatedContext::Instance {
99 public:
100 enum PathType {
101 PLATFORM_PATH,
102 VIRTUAL_PATH
105 // For a single-path isolated file system, which could be registered by
106 // IsolatedContext::RegisterFileSystemForPath() or
107 // IsolatedContext::RegisterFileSystemForVirtualPath().
108 // Most of isolated file system contexts should be of this type.
109 Instance(FileSystemType type,
110 const std::string& filesystem_id,
111 const MountPointInfo& file_info,
112 PathType path_type);
114 // For a multi-paths isolated file system. As of writing only file system
115 // type which could have multi-paths is Dragged file system, and
116 // could be registered by IsolatedContext::RegisterDraggedFileSystem().
117 Instance(FileSystemType type, const std::set<MountPointInfo>& files);
119 ~Instance();
121 FileSystemType type() const { return type_; }
122 const std::string& filesystem_id() const { return filesystem_id_; }
123 const MountPointInfo& file_info() const { return file_info_; }
124 const std::set<MountPointInfo>& files() const { return files_; }
125 int ref_counts() const { return ref_counts_; }
127 void AddRef() { ++ref_counts_; }
128 void RemoveRef() { --ref_counts_; }
130 bool ResolvePathForName(const std::string& name, base::FilePath* path) const;
132 // Returns true if the instance is a single-path instance.
133 bool IsSinglePathInstance() const;
135 private:
136 const FileSystemType type_;
137 const std::string filesystem_id_;
139 // For single-path instance.
140 const MountPointInfo file_info_;
141 const PathType path_type_;
143 // For multiple-path instance (e.g. dragged file system).
144 const std::set<MountPointInfo> files_;
146 // Reference counts. Note that an isolated filesystem is created with ref==0
147 // and will get deleted when the ref count reaches <=0.
148 int ref_counts_;
150 DISALLOW_COPY_AND_ASSIGN(Instance);
153 IsolatedContext::Instance::Instance(FileSystemType type,
154 const std::string& filesystem_id,
155 const MountPointInfo& file_info,
156 Instance::PathType path_type)
157 : type_(type),
158 filesystem_id_(filesystem_id),
159 file_info_(file_info),
160 path_type_(path_type),
161 ref_counts_(0) {
162 DCHECK(IsSinglePathIsolatedFileSystem(type_));
165 IsolatedContext::Instance::Instance(FileSystemType type,
166 const std::set<MountPointInfo>& files)
167 : type_(type),
168 path_type_(PLATFORM_PATH),
169 files_(files),
170 ref_counts_(0) {
171 DCHECK(!IsSinglePathIsolatedFileSystem(type_));
174 IsolatedContext::Instance::~Instance() {}
176 bool IsolatedContext::Instance::ResolvePathForName(const std::string& name,
177 base::FilePath* path) const {
178 if (IsSinglePathIsolatedFileSystem(type_)) {
179 switch (path_type_) {
180 case PLATFORM_PATH:
181 *path = file_info_.path;
182 break;
183 case VIRTUAL_PATH:
184 *path = base::FilePath();
185 break;
186 default:
187 NOTREACHED();
190 return file_info_.name == name;
192 std::set<MountPointInfo>::const_iterator found = files_.find(
193 MountPointInfo(name, base::FilePath()));
194 if (found == files_.end())
195 return false;
196 *path = found->path;
197 return true;
200 bool IsolatedContext::Instance::IsSinglePathInstance() const {
201 return IsSinglePathIsolatedFileSystem(type_);
204 //--------------------------------------------------------------------------
206 // static
207 IsolatedContext* IsolatedContext::GetInstance() {
208 return g_isolated_context.Pointer();
211 // static
212 bool IsolatedContext::IsIsolatedType(FileSystemType type) {
213 return type == kFileSystemTypeIsolated || type == kFileSystemTypeExternal;
216 std::string IsolatedContext::RegisterDraggedFileSystem(
217 const FileInfoSet& files) {
218 base::AutoLock locker(lock_);
219 std::string filesystem_id = GetNewFileSystemId();
220 instance_map_[filesystem_id] = new Instance(
221 kFileSystemTypeDragged, files.fileset());
222 return filesystem_id;
225 std::string IsolatedContext::RegisterFileSystemForPath(
226 FileSystemType type,
227 const std::string& filesystem_id,
228 const base::FilePath& path_in,
229 std::string* register_name) {
230 base::FilePath path(path_in.NormalizePathSeparators());
231 if (path.ReferencesParent() || !path.IsAbsolute())
232 return std::string();
233 std::string name;
234 if (register_name && !register_name->empty()) {
235 name = *register_name;
236 } else {
237 name = base::FilePath(GetRegisterNameForPath(path)).AsUTF8Unsafe();
238 if (register_name)
239 register_name->assign(name);
242 base::AutoLock locker(lock_);
243 std::string new_id = GetNewFileSystemId();
244 instance_map_[new_id] = new Instance(type, filesystem_id,
245 MountPointInfo(name, path),
246 Instance::PLATFORM_PATH);
247 path_to_id_map_[path].insert(new_id);
248 return new_id;
251 std::string IsolatedContext::RegisterFileSystemForVirtualPath(
252 FileSystemType type,
253 const std::string& register_name,
254 const base::FilePath& cracked_path_prefix) {
255 base::AutoLock locker(lock_);
256 base::FilePath path(cracked_path_prefix.NormalizePathSeparators());
257 if (path.ReferencesParent())
258 return std::string();
259 std::string filesystem_id = GetNewFileSystemId();
260 instance_map_[filesystem_id] = new Instance(
261 type,
262 std::string(), // filesystem_id
263 MountPointInfo(register_name, cracked_path_prefix),
264 Instance::VIRTUAL_PATH);
265 path_to_id_map_[path].insert(filesystem_id);
266 return filesystem_id;
269 bool IsolatedContext::HandlesFileSystemMountType(FileSystemType type) const {
270 return type == kFileSystemTypeIsolated;
273 bool IsolatedContext::RevokeFileSystem(const std::string& filesystem_id) {
274 base::AutoLock locker(lock_);
275 return UnregisterFileSystem(filesystem_id);
278 bool IsolatedContext::GetRegisteredPath(
279 const std::string& filesystem_id, base::FilePath* path) const {
280 DCHECK(path);
281 base::AutoLock locker(lock_);
282 IDToInstance::const_iterator found = instance_map_.find(filesystem_id);
283 if (found == instance_map_.end() || !found->second->IsSinglePathInstance())
284 return false;
285 *path = found->second->file_info().path;
286 return true;
289 bool IsolatedContext::CrackVirtualPath(
290 const base::FilePath& virtual_path,
291 std::string* id_or_name,
292 FileSystemType* type,
293 std::string* cracked_id,
294 base::FilePath* path,
295 FileSystemMountOption* mount_option) const {
296 DCHECK(id_or_name);
297 DCHECK(path);
299 // This should not contain any '..' references.
300 if (virtual_path.ReferencesParent())
301 return false;
303 // Set the default mount option.
304 *mount_option = FileSystemMountOption();
306 // The virtual_path should comprise <id_or_name> and <relative_path> parts.
307 std::vector<base::FilePath::StringType> components;
308 virtual_path.GetComponents(&components);
309 if (components.size() < 1)
310 return false;
311 std::vector<base::FilePath::StringType>::iterator component_iter =
312 components.begin();
313 std::string fsid = base::FilePath(*component_iter++).MaybeAsASCII();
314 if (fsid.empty())
315 return false;
317 base::FilePath cracked_path;
319 base::AutoLock locker(lock_);
320 IDToInstance::const_iterator found_instance = instance_map_.find(fsid);
321 if (found_instance == instance_map_.end())
322 return false;
323 *id_or_name = fsid;
324 const Instance* instance = found_instance->second;
325 if (type)
326 *type = instance->type();
327 if (cracked_id)
328 *cracked_id = instance->filesystem_id();
330 if (component_iter == components.end()) {
331 // The virtual root case.
332 path->clear();
333 return true;
336 // *component_iter should be a name of the registered path.
337 std::string name = base::FilePath(*component_iter++).AsUTF8Unsafe();
338 if (!instance->ResolvePathForName(name, &cracked_path))
339 return false;
342 for (; component_iter != components.end(); ++component_iter)
343 cracked_path = cracked_path.Append(*component_iter);
344 *path = cracked_path;
345 return true;
348 FileSystemURL IsolatedContext::CrackURL(const GURL& url) const {
349 FileSystemURL filesystem_url = FileSystemURL(url);
350 if (!filesystem_url.is_valid())
351 return FileSystemURL();
352 return CrackFileSystemURL(filesystem_url);
355 FileSystemURL IsolatedContext::CreateCrackedFileSystemURL(
356 const GURL& origin,
357 FileSystemType type,
358 const base::FilePath& path) const {
359 return CrackFileSystemURL(FileSystemURL(origin, type, path));
362 void IsolatedContext::RevokeFileSystemByPath(const base::FilePath& path_in) {
363 base::AutoLock locker(lock_);
364 base::FilePath path(path_in.NormalizePathSeparators());
365 PathToID::iterator ids_iter = path_to_id_map_.find(path);
366 if (ids_iter == path_to_id_map_.end())
367 return;
368 std::set<std::string>& ids = ids_iter->second;
369 for (std::set<std::string>::iterator iter = ids.begin();
370 iter != ids.end(); ++iter) {
371 IDToInstance::iterator found = instance_map_.find(*iter);
372 if (found != instance_map_.end()) {
373 delete found->second;
374 instance_map_.erase(found);
377 path_to_id_map_.erase(ids_iter);
380 void IsolatedContext::AddReference(const std::string& filesystem_id) {
381 base::AutoLock locker(lock_);
382 DCHECK(instance_map_.find(filesystem_id) != instance_map_.end());
383 instance_map_[filesystem_id]->AddRef();
386 void IsolatedContext::RemoveReference(const std::string& filesystem_id) {
387 base::AutoLock locker(lock_);
388 // This could get called for non-existent filesystem if it has been
389 // already deleted by RevokeFileSystemByPath.
390 IDToInstance::iterator found = instance_map_.find(filesystem_id);
391 if (found == instance_map_.end())
392 return;
393 Instance* instance = found->second;
394 DCHECK_GT(instance->ref_counts(), 0);
395 instance->RemoveRef();
396 if (instance->ref_counts() == 0) {
397 bool deleted = UnregisterFileSystem(filesystem_id);
398 DCHECK(deleted);
402 bool IsolatedContext::GetDraggedFileInfo(
403 const std::string& filesystem_id,
404 std::vector<MountPointInfo>* files) const {
405 DCHECK(files);
406 base::AutoLock locker(lock_);
407 IDToInstance::const_iterator found = instance_map_.find(filesystem_id);
408 if (found == instance_map_.end() ||
409 found->second->type() != kFileSystemTypeDragged)
410 return false;
411 files->assign(found->second->files().begin(),
412 found->second->files().end());
413 return true;
416 base::FilePath IsolatedContext::CreateVirtualRootPath(
417 const std::string& filesystem_id) const {
418 return base::FilePath().AppendASCII(filesystem_id);
421 IsolatedContext::IsolatedContext() {
424 IsolatedContext::~IsolatedContext() {
425 STLDeleteContainerPairSecondPointers(instance_map_.begin(),
426 instance_map_.end());
429 FileSystemURL IsolatedContext::CrackFileSystemURL(
430 const FileSystemURL& url) const {
431 if (!HandlesFileSystemMountType(url.type()))
432 return FileSystemURL();
434 std::string mount_name;
435 std::string cracked_mount_name;
436 FileSystemType cracked_type;
437 base::FilePath cracked_path;
438 FileSystemMountOption cracked_mount_option;
439 if (!CrackVirtualPath(url.path(), &mount_name, &cracked_type,
440 &cracked_mount_name, &cracked_path,
441 &cracked_mount_option)) {
442 return FileSystemURL();
445 return FileSystemURL(
446 url.origin(), url.mount_type(), url.virtual_path(),
447 !url.filesystem_id().empty() ? url.filesystem_id() : mount_name,
448 cracked_type, cracked_path,
449 cracked_mount_name.empty() ? mount_name : cracked_mount_name,
450 cracked_mount_option);
453 bool IsolatedContext::UnregisterFileSystem(const std::string& filesystem_id) {
454 lock_.AssertAcquired();
455 IDToInstance::iterator found = instance_map_.find(filesystem_id);
456 if (found == instance_map_.end())
457 return false;
458 Instance* instance = found->second;
459 if (instance->IsSinglePathInstance()) {
460 PathToID::iterator ids_iter = path_to_id_map_.find(
461 instance->file_info().path);
462 DCHECK(ids_iter != path_to_id_map_.end());
463 ids_iter->second.erase(filesystem_id);
464 if (ids_iter->second.empty())
465 path_to_id_map_.erase(ids_iter);
467 delete found->second;
468 instance_map_.erase(found);
469 return true;
472 std::string IsolatedContext::GetNewFileSystemId() const {
473 // Returns an arbitrary random string which must be unique in the map.
474 lock_.AssertAcquired();
475 uint32 random_data[4];
476 std::string id;
477 do {
478 base::RandBytes(random_data, sizeof(random_data));
479 id = base::HexEncode(random_data, sizeof(random_data));
480 } while (instance_map_.find(id) != instance_map_.end());
481 return id;
484 } // namespace storage