Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / webkit / fileapi / external_mount_points.cc
blobb0c18dea92bec4f0b773cadb0cf00676d4ab0102
1 // Copyright (c) 2013 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 "webkit/fileapi/external_mount_points.h"
7 #include "base/files/file_path.h"
8 #include "base/lazy_instance.h"
9 #include "base/path_service.h"
10 #include "base/stl_util.h"
11 #include "webkit/fileapi/file_system_url.h"
12 #include "webkit/fileapi/remote_file_system_proxy.h"
14 namespace {
16 // Normalizes file path so it has normalized separators and ends with exactly
17 // one separator. Paths have to be normalized this way for use in
18 // GetVirtualPath method. Separators cannot be completely stripped, or
19 // GetVirtualPath could not working in some edge cases.
20 // For example, /a/b/c(1)/d would be erroneously resolved as c/d if the
21 // following mount points were registered: "/a/b/c", "/a/b/c(1)". (Note:
22 // "/a/b/c" < "/a/b/c(1)" < "/a/b/c/").
23 base::FilePath NormalizeFilePath(const base::FilePath& path) {
24 if (path.empty())
25 return path;
27 base::FilePath::StringType path_str = path.StripTrailingSeparators().value();
28 if (!base::FilePath::IsSeparator(path_str[path_str.length() - 1]))
29 path_str.append(FILE_PATH_LITERAL("/"));
31 return base::FilePath(path_str).NormalizePathSeparators();
34 // Wrapper around ref-counted ExternalMountPoints that will be used to lazily
35 // create and initialize LazyInstance system ExternalMountPoints.
36 class SystemMountPointsLazyWrapper {
37 public:
38 SystemMountPointsLazyWrapper()
39 : system_mount_points_(fileapi::ExternalMountPoints::CreateRefCounted()) {
42 ~SystemMountPointsLazyWrapper() {}
44 fileapi::ExternalMountPoints* get() {
45 return system_mount_points_.get();
48 private:
49 scoped_refptr<fileapi::ExternalMountPoints> system_mount_points_;
52 base::LazyInstance<SystemMountPointsLazyWrapper>::Leaky
53 g_external_mount_points = LAZY_INSTANCE_INITIALIZER;
55 } // namespace
57 namespace fileapi {
59 class ExternalMountPoints::Instance {
60 public:
61 Instance(FileSystemType type,
62 const base::FilePath& path,
63 RemoteFileSystemProxyInterface* remote_proxy);
65 ~Instance();
67 FileSystemType type() const { return type_; }
68 const base::FilePath& path() const { return path_; }
69 RemoteFileSystemProxyInterface* remote_proxy() const {
70 return remote_proxy_.get();
73 private:
74 const FileSystemType type_;
75 const base::FilePath path_;
77 // For file systems that have a remote file system proxy.
78 scoped_refptr<RemoteFileSystemProxyInterface> remote_proxy_;
80 DISALLOW_COPY_AND_ASSIGN(Instance);
83 ExternalMountPoints::Instance::Instance(FileSystemType type,
84 const base::FilePath& path,
85 RemoteFileSystemProxyInterface* proxy)
86 : type_(type),
87 path_(path.StripTrailingSeparators()),
88 remote_proxy_(proxy) {
89 DCHECK(!proxy || (kFileSystemTypeDrive == type_));
92 ExternalMountPoints::Instance::~Instance() {}
94 //--------------------------------------------------------------------------
96 // static
97 ExternalMountPoints* ExternalMountPoints::GetSystemInstance() {
98 return g_external_mount_points.Pointer()->get();
101 // static
102 scoped_refptr<ExternalMountPoints> ExternalMountPoints::CreateRefCounted() {
103 return new ExternalMountPoints();
106 bool ExternalMountPoints::RegisterFileSystem(
107 const std::string& mount_name,
108 FileSystemType type,
109 const base::FilePath& path) {
110 return RegisterRemoteFileSystem(mount_name, type, NULL, path);
113 bool ExternalMountPoints::RegisterRemoteFileSystem(
114 const std::string& mount_name,
115 FileSystemType type,
116 RemoteFileSystemProxyInterface* remote_proxy,
117 const base::FilePath& path_in) {
118 base::AutoLock locker(lock_);
120 base::FilePath path = NormalizeFilePath(path_in);
121 if (!ValidateNewMountPoint(mount_name, path))
122 return false;
124 instance_map_[mount_name] = new Instance(type, path, remote_proxy);
125 if (!path.empty())
126 path_to_name_map_.insert(std::make_pair(path, mount_name));
127 return true;
130 bool ExternalMountPoints::HandlesFileSystemMountType(
131 FileSystemType type) const {
132 return type == kFileSystemTypeExternal ||
133 type == kFileSystemTypeNativeForPlatformApp;
136 bool ExternalMountPoints::RevokeFileSystem(const std::string& mount_name) {
137 base::AutoLock locker(lock_);
138 NameToInstance::iterator found = instance_map_.find(mount_name);
139 if (found == instance_map_.end())
140 return false;
141 Instance* instance = found->second;
142 path_to_name_map_.erase(NormalizeFilePath(instance->path()));
143 delete found->second;
144 instance_map_.erase(found);
145 return true;
148 bool ExternalMountPoints::GetRegisteredPath(
149 const std::string& filesystem_id, base::FilePath* path) const {
150 DCHECK(path);
151 base::AutoLock locker(lock_);
152 NameToInstance::const_iterator found = instance_map_.find(filesystem_id);
153 if (found == instance_map_.end())
154 return false;
155 *path = found->second->path();
156 return true;
159 bool ExternalMountPoints::CrackVirtualPath(const base::FilePath& virtual_path,
160 std::string* mount_name,
161 FileSystemType* type,
162 base::FilePath* path) const {
163 DCHECK(mount_name);
164 DCHECK(path);
166 // The path should not contain any '..' references.
167 if (virtual_path.ReferencesParent())
168 return false;
170 // The virtual_path should comprise of <mount_name> and <relative_path> parts.
171 std::vector<base::FilePath::StringType> components;
172 virtual_path.GetComponents(&components);
173 if (components.size() < 1)
174 return false;
176 std::vector<base::FilePath::StringType>::iterator component_iter =
177 components.begin();
178 std::string maybe_mount_name = base::FilePath(*component_iter++).MaybeAsASCII();
179 if (maybe_mount_name.empty())
180 return false;
182 base::FilePath cracked_path;
184 base::AutoLock locker(lock_);
185 NameToInstance::const_iterator found_instance =
186 instance_map_.find(maybe_mount_name);
187 if (found_instance == instance_map_.end())
188 return false;
190 *mount_name = maybe_mount_name;
191 const Instance* instance = found_instance->second;
192 if (type)
193 *type = instance->type();
194 cracked_path = instance->path();
197 for (; component_iter != components.end(); ++component_iter)
198 cracked_path = cracked_path.Append(*component_iter);
199 *path = cracked_path;
200 return true;
203 FileSystemURL ExternalMountPoints::CrackURL(const GURL& url) const {
204 FileSystemURL filesystem_url = FileSystemURL(url);
205 if (!filesystem_url.is_valid())
206 return FileSystemURL();
207 return CrackFileSystemURL(filesystem_url);
210 FileSystemURL ExternalMountPoints::CreateCrackedFileSystemURL(
211 const GURL& origin,
212 FileSystemType type,
213 const base::FilePath& path) const {
214 return CrackFileSystemURL(FileSystemURL(origin, type, path));
217 RemoteFileSystemProxyInterface* ExternalMountPoints::GetRemoteFileSystemProxy(
218 const std::string& mount_name) const {
219 base::AutoLock locker(lock_);
220 NameToInstance::const_iterator found = instance_map_.find(mount_name);
221 if (found == instance_map_.end())
222 return NULL;
223 return found->second->remote_proxy();
226 void ExternalMountPoints::AddMountPointInfosTo(
227 std::vector<MountPointInfo>* mount_points) const {
228 base::AutoLock locker(lock_);
229 DCHECK(mount_points);
230 for (NameToInstance::const_iterator iter = instance_map_.begin();
231 iter != instance_map_.end(); ++iter) {
232 mount_points->push_back(MountPointInfo(iter->first, iter->second->path()));
236 bool ExternalMountPoints::GetVirtualPath(const base::FilePath& path_in,
237 base::FilePath* virtual_path) const {
238 DCHECK(virtual_path);
240 base::AutoLock locker(lock_);
242 base::FilePath path = NormalizeFilePath(path_in);
243 std::map<base::FilePath, std::string>::const_reverse_iterator iter(
244 path_to_name_map_.upper_bound(path));
245 if (iter == path_to_name_map_.rend())
246 return false;
248 *virtual_path = CreateVirtualRootPath(iter->second);
249 if (iter->first == path)
250 return true;
251 return iter->first.AppendRelativePath(path, virtual_path);
254 base::FilePath ExternalMountPoints::CreateVirtualRootPath(
255 const std::string& mount_name) const {
256 return base::FilePath().AppendASCII(mount_name);
259 ExternalMountPoints::ExternalMountPoints() {}
261 ExternalMountPoints::~ExternalMountPoints() {
262 STLDeleteContainerPairSecondPointers(instance_map_.begin(),
263 instance_map_.end());
266 FileSystemURL ExternalMountPoints::CrackFileSystemURL(
267 const FileSystemURL& url) const {
268 if (!HandlesFileSystemMountType(url.type()))
269 return FileSystemURL();
271 base::FilePath virtual_path = url.path();
272 if (url.type() == kFileSystemTypeNativeForPlatformApp) {
273 #if defined(OS_CHROMEOS)
274 // On Chrome OS, find a mount point and virtual path for the external fs.
275 if (!GetVirtualPath(url.path(), &virtual_path))
276 return FileSystemURL();
277 #else
278 // On other OS, it is simply a native local path.
279 return FileSystemURL(
280 url.origin(), url.mount_type(), url.virtual_path(),
281 url.mount_filesystem_id(), kFileSystemTypeNativeLocal,
282 url.path(), url.filesystem_id());
283 #endif
286 std::string mount_name;
287 FileSystemType cracked_type;
288 base::FilePath cracked_path;
290 if (!CrackVirtualPath(virtual_path, &mount_name, &cracked_type,
291 &cracked_path)) {
292 return FileSystemURL();
295 return FileSystemURL(
296 url.origin(), url.mount_type(), url.virtual_path(),
297 !url.filesystem_id().empty() ? url.filesystem_id() : mount_name,
298 cracked_type, cracked_path, mount_name);
301 bool ExternalMountPoints::ValidateNewMountPoint(const std::string& mount_name,
302 const base::FilePath& path) {
303 lock_.AssertAcquired();
305 // Mount name must not be empty.
306 if (mount_name.empty())
307 return false;
309 // Verify there is no registered mount point with the same name.
310 NameToInstance::iterator found = instance_map_.find(mount_name);
311 if (found != instance_map_.end())
312 return false;
314 // Allow empty paths.
315 if (path.empty())
316 return true;
318 // Verify path is legal.
319 if (path.ReferencesParent() || !path.IsAbsolute())
320 return false;
322 // Check there the new path does not overlap with one of the existing ones.
323 std::map<base::FilePath, std::string>::reverse_iterator potential_parent(
324 path_to_name_map_.upper_bound(path));
325 if (potential_parent != path_to_name_map_.rend()) {
326 if (potential_parent->first == path ||
327 potential_parent->first.IsParent(path)) {
328 return false;
332 std::map<base::FilePath, std::string>::iterator potential_child =
333 path_to_name_map_.upper_bound(path);
334 if (potential_child == path_to_name_map_.end())
335 return true;
336 return !(potential_child->first == path) &&
337 !path.IsParent(potential_child->first);
340 ScopedExternalFileSystem::ScopedExternalFileSystem(
341 const std::string& mount_name,
342 FileSystemType type,
343 const base::FilePath& path)
344 : mount_name_(mount_name) {
345 ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
346 mount_name, type, path);
349 base::FilePath ScopedExternalFileSystem::GetVirtualRootPath() const {
350 return ExternalMountPoints::GetSystemInstance()->
351 CreateVirtualRootPath(mount_name_);
354 ScopedExternalFileSystem::~ScopedExternalFileSystem() {
355 ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(mount_name_);
358 } // namespace fileapi