OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "webkit/browser/fileapi/external_mount_points.h" | |
6 | |
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/browser/fileapi/file_system_url.h" | |
12 | |
13 namespace { | |
14 | |
15 // Normalizes file path so it has normalized separators and ends with exactly | |
16 // one separator. Paths have to be normalized this way for use in | |
17 // GetVirtualPath method. Separators cannot be completely stripped, or | |
18 // GetVirtualPath could not working in some edge cases. | |
19 // For example, /a/b/c(1)/d would be erroneously resolved as c/d if the | |
20 // following mount points were registered: "/a/b/c", "/a/b/c(1)". (Note: | |
21 // "/a/b/c" < "/a/b/c(1)" < "/a/b/c/"). | |
22 base::FilePath NormalizeFilePath(const base::FilePath& path) { | |
23 if (path.empty()) | |
24 return path; | |
25 | |
26 base::FilePath::StringType path_str = path.StripTrailingSeparators().value(); | |
27 if (!base::FilePath::IsSeparator(path_str[path_str.length() - 1])) | |
28 path_str.append(FILE_PATH_LITERAL("/")); | |
29 | |
30 return base::FilePath(path_str).NormalizePathSeparators(); | |
31 } | |
32 | |
33 bool IsOverlappingMountPathForbidden(fileapi::FileSystemType type) { | |
34 return type != fileapi::kFileSystemTypeNativeMedia && | |
35 type != fileapi::kFileSystemTypeDeviceMedia; | |
36 } | |
37 | |
38 // Wrapper around ref-counted ExternalMountPoints that will be used to lazily | |
39 // create and initialize LazyInstance system ExternalMountPoints. | |
40 class SystemMountPointsLazyWrapper { | |
41 public: | |
42 SystemMountPointsLazyWrapper() | |
43 : system_mount_points_(fileapi::ExternalMountPoints::CreateRefCounted()) { | |
44 } | |
45 | |
46 ~SystemMountPointsLazyWrapper() {} | |
47 | |
48 fileapi::ExternalMountPoints* get() { | |
49 return system_mount_points_.get(); | |
50 } | |
51 | |
52 private: | |
53 scoped_refptr<fileapi::ExternalMountPoints> system_mount_points_; | |
54 }; | |
55 | |
56 base::LazyInstance<SystemMountPointsLazyWrapper>::Leaky | |
57 g_external_mount_points = LAZY_INSTANCE_INITIALIZER; | |
58 | |
59 } // namespace | |
60 | |
61 namespace fileapi { | |
62 | |
63 class ExternalMountPoints::Instance { | |
64 public: | |
65 Instance(FileSystemType type, | |
66 const base::FilePath& path, | |
67 const FileSystemMountOption& mount_option) | |
68 : type_(type), | |
69 path_(path.StripTrailingSeparators()), | |
70 mount_option_(mount_option) {} | |
71 ~Instance() {} | |
72 | |
73 FileSystemType type() const { return type_; } | |
74 const base::FilePath& path() const { return path_; } | |
75 const FileSystemMountOption& mount_option() const { return mount_option_; } | |
76 | |
77 private: | |
78 const FileSystemType type_; | |
79 const base::FilePath path_; | |
80 const FileSystemMountOption mount_option_; | |
81 | |
82 DISALLOW_COPY_AND_ASSIGN(Instance); | |
83 }; | |
84 | |
85 //-------------------------------------------------------------------------- | |
86 | |
87 // static | |
88 ExternalMountPoints* ExternalMountPoints::GetSystemInstance() { | |
89 return g_external_mount_points.Pointer()->get(); | |
90 } | |
91 | |
92 // static | |
93 scoped_refptr<ExternalMountPoints> ExternalMountPoints::CreateRefCounted() { | |
94 return new ExternalMountPoints(); | |
95 } | |
96 | |
97 bool ExternalMountPoints::RegisterFileSystem( | |
98 const std::string& mount_name, | |
99 FileSystemType type, | |
100 const FileSystemMountOption& mount_option, | |
101 const base::FilePath& path_in) { | |
102 // COPY_SYNC_OPTION_SYNC is only applicable to native local file system. | |
103 DCHECK(type == kFileSystemTypeNativeLocal || | |
104 mount_option.copy_sync_option() != COPY_SYNC_OPTION_SYNC); | |
105 | |
106 base::AutoLock locker(lock_); | |
107 | |
108 base::FilePath path = NormalizeFilePath(path_in); | |
109 if (!ValidateNewMountPoint(mount_name, type, path)) | |
110 return false; | |
111 | |
112 instance_map_[mount_name] = new Instance(type, path, mount_option); | |
113 if (!path.empty() && IsOverlappingMountPathForbidden(type)) | |
114 path_to_name_map_.insert(std::make_pair(path, mount_name)); | |
115 return true; | |
116 } | |
117 | |
118 bool ExternalMountPoints::HandlesFileSystemMountType( | |
119 FileSystemType type) const { | |
120 return type == kFileSystemTypeExternal || | |
121 type == kFileSystemTypeNativeForPlatformApp; | |
122 } | |
123 | |
124 bool ExternalMountPoints::RevokeFileSystem(const std::string& mount_name) { | |
125 base::AutoLock locker(lock_); | |
126 NameToInstance::iterator found = instance_map_.find(mount_name); | |
127 if (found == instance_map_.end()) | |
128 return false; | |
129 Instance* instance = found->second; | |
130 if (IsOverlappingMountPathForbidden(instance->type())) | |
131 path_to_name_map_.erase(NormalizeFilePath(instance->path())); | |
132 delete found->second; | |
133 instance_map_.erase(found); | |
134 return true; | |
135 } | |
136 | |
137 bool ExternalMountPoints::GetRegisteredPath( | |
138 const std::string& filesystem_id, base::FilePath* path) const { | |
139 DCHECK(path); | |
140 base::AutoLock locker(lock_); | |
141 NameToInstance::const_iterator found = instance_map_.find(filesystem_id); | |
142 if (found == instance_map_.end()) | |
143 return false; | |
144 *path = found->second->path(); | |
145 return true; | |
146 } | |
147 | |
148 bool ExternalMountPoints::CrackVirtualPath( | |
149 const base::FilePath& virtual_path, | |
150 std::string* mount_name, | |
151 FileSystemType* type, | |
152 std::string* cracked_id, | |
153 base::FilePath* path, | |
154 FileSystemMountOption* mount_option) const { | |
155 DCHECK(mount_name); | |
156 DCHECK(path); | |
157 | |
158 // The path should not contain any '..' references. | |
159 if (virtual_path.ReferencesParent()) | |
160 return false; | |
161 | |
162 // The virtual_path should comprise of <mount_name> and <relative_path> parts. | |
163 std::vector<base::FilePath::StringType> components; | |
164 virtual_path.GetComponents(&components); | |
165 if (components.size() < 1) | |
166 return false; | |
167 | |
168 std::vector<base::FilePath::StringType>::iterator component_iter = | |
169 components.begin(); | |
170 std::string maybe_mount_name = | |
171 base::FilePath(*component_iter++).MaybeAsASCII(); | |
172 if (maybe_mount_name.empty()) | |
173 return false; | |
174 | |
175 base::FilePath cracked_path; | |
176 { | |
177 base::AutoLock locker(lock_); | |
178 NameToInstance::const_iterator found_instance = | |
179 instance_map_.find(maybe_mount_name); | |
180 if (found_instance == instance_map_.end()) | |
181 return false; | |
182 | |
183 *mount_name = maybe_mount_name; | |
184 const Instance* instance = found_instance->second; | |
185 if (type) | |
186 *type = instance->type(); | |
187 cracked_path = instance->path(); | |
188 *mount_option = instance->mount_option(); | |
189 } | |
190 | |
191 for (; component_iter != components.end(); ++component_iter) | |
192 cracked_path = cracked_path.Append(*component_iter); | |
193 *path = cracked_path; | |
194 return true; | |
195 } | |
196 | |
197 FileSystemURL ExternalMountPoints::CrackURL(const GURL& url) const { | |
198 FileSystemURL filesystem_url = FileSystemURL(url); | |
199 if (!filesystem_url.is_valid()) | |
200 return FileSystemURL(); | |
201 return CrackFileSystemURL(filesystem_url); | |
202 } | |
203 | |
204 FileSystemURL ExternalMountPoints::CreateCrackedFileSystemURL( | |
205 const GURL& origin, | |
206 FileSystemType type, | |
207 const base::FilePath& path) const { | |
208 return CrackFileSystemURL(FileSystemURL(origin, type, path)); | |
209 } | |
210 | |
211 void ExternalMountPoints::AddMountPointInfosTo( | |
212 std::vector<MountPointInfo>* mount_points) const { | |
213 base::AutoLock locker(lock_); | |
214 DCHECK(mount_points); | |
215 for (NameToInstance::const_iterator iter = instance_map_.begin(); | |
216 iter != instance_map_.end(); ++iter) { | |
217 mount_points->push_back(MountPointInfo(iter->first, iter->second->path())); | |
218 } | |
219 } | |
220 | |
221 bool ExternalMountPoints::GetVirtualPath(const base::FilePath& path_in, | |
222 base::FilePath* virtual_path) const { | |
223 DCHECK(virtual_path); | |
224 | |
225 base::AutoLock locker(lock_); | |
226 | |
227 base::FilePath path = NormalizeFilePath(path_in); | |
228 std::map<base::FilePath, std::string>::const_reverse_iterator iter( | |
229 path_to_name_map_.upper_bound(path)); | |
230 if (iter == path_to_name_map_.rend()) | |
231 return false; | |
232 | |
233 *virtual_path = CreateVirtualRootPath(iter->second); | |
234 if (iter->first == path) | |
235 return true; | |
236 return iter->first.AppendRelativePath(path, virtual_path); | |
237 } | |
238 | |
239 base::FilePath ExternalMountPoints::CreateVirtualRootPath( | |
240 const std::string& mount_name) const { | |
241 return base::FilePath().AppendASCII(mount_name); | |
242 } | |
243 | |
244 FileSystemURL ExternalMountPoints::CreateExternalFileSystemURL( | |
245 const GURL& origin, | |
246 const std::string& mount_name, | |
247 const base::FilePath& path) const { | |
248 return CreateCrackedFileSystemURL( | |
249 origin, | |
250 fileapi::kFileSystemTypeExternal, | |
251 // Avoid using FilePath::Append as path may be an absolute path. | |
252 base::FilePath( | |
253 CreateVirtualRootPath(mount_name).value() + | |
254 base::FilePath::kSeparators[0] + path.value())); | |
255 } | |
256 | |
257 void ExternalMountPoints::RevokeAllFileSystems() { | |
258 NameToInstance instance_map_copy; | |
259 { | |
260 base::AutoLock locker(lock_); | |
261 instance_map_copy = instance_map_; | |
262 instance_map_.clear(); | |
263 path_to_name_map_.clear(); | |
264 } | |
265 STLDeleteContainerPairSecondPointers(instance_map_copy.begin(), | |
266 instance_map_copy.end()); | |
267 } | |
268 | |
269 ExternalMountPoints::ExternalMountPoints() {} | |
270 | |
271 ExternalMountPoints::~ExternalMountPoints() { | |
272 STLDeleteContainerPairSecondPointers(instance_map_.begin(), | |
273 instance_map_.end()); | |
274 } | |
275 | |
276 FileSystemURL ExternalMountPoints::CrackFileSystemURL( | |
277 const FileSystemURL& url) const { | |
278 if (!HandlesFileSystemMountType(url.type())) | |
279 return FileSystemURL(); | |
280 | |
281 base::FilePath virtual_path = url.path(); | |
282 if (url.type() == kFileSystemTypeNativeForPlatformApp) { | |
283 #if defined(OS_CHROMEOS) | |
284 // On Chrome OS, find a mount point and virtual path for the external fs. | |
285 if (!GetVirtualPath(url.path(), &virtual_path)) | |
286 return FileSystemURL(); | |
287 #else | |
288 // On other OS, it is simply a native local path. | |
289 return FileSystemURL( | |
290 url.origin(), url.mount_type(), url.virtual_path(), | |
291 url.mount_filesystem_id(), kFileSystemTypeNativeLocal, | |
292 url.path(), url.filesystem_id(), url.mount_option()); | |
293 #endif | |
294 } | |
295 | |
296 std::string mount_name; | |
297 FileSystemType cracked_type; | |
298 std::string cracked_id; | |
299 base::FilePath cracked_path; | |
300 FileSystemMountOption cracked_mount_option; | |
301 | |
302 if (!CrackVirtualPath(virtual_path, &mount_name, &cracked_type, | |
303 &cracked_id, &cracked_path, &cracked_mount_option)) { | |
304 return FileSystemURL(); | |
305 } | |
306 | |
307 return FileSystemURL( | |
308 url.origin(), url.mount_type(), url.virtual_path(), | |
309 !url.filesystem_id().empty() ? url.filesystem_id() : mount_name, | |
310 cracked_type, cracked_path, | |
311 cracked_id.empty() ? mount_name : cracked_id, cracked_mount_option); | |
312 } | |
313 | |
314 bool ExternalMountPoints::ValidateNewMountPoint(const std::string& mount_name, | |
315 FileSystemType type, | |
316 const base::FilePath& path) { | |
317 lock_.AssertAcquired(); | |
318 | |
319 // Mount name must not be empty. | |
320 if (mount_name.empty()) | |
321 return false; | |
322 | |
323 // Verify there is no registered mount point with the same name. | |
324 NameToInstance::iterator found = instance_map_.find(mount_name); | |
325 if (found != instance_map_.end()) | |
326 return false; | |
327 | |
328 // Allow empty paths. | |
329 if (path.empty()) | |
330 return true; | |
331 | |
332 // Verify path is legal. | |
333 if (path.ReferencesParent() || !path.IsAbsolute()) | |
334 return false; | |
335 | |
336 if (IsOverlappingMountPathForbidden(type)) { | |
337 // Check there the new path does not overlap with one of the existing ones. | |
338 std::map<base::FilePath, std::string>::reverse_iterator potential_parent( | |
339 path_to_name_map_.upper_bound(path)); | |
340 if (potential_parent != path_to_name_map_.rend()) { | |
341 if (potential_parent->first == path || | |
342 potential_parent->first.IsParent(path)) { | |
343 return false; | |
344 } | |
345 } | |
346 | |
347 std::map<base::FilePath, std::string>::iterator potential_child = | |
348 path_to_name_map_.upper_bound(path); | |
349 if (potential_child != path_to_name_map_.end()) { | |
350 if (potential_child->first == path || | |
351 path.IsParent(potential_child->first)) { | |
352 return false; | |
353 } | |
354 } | |
355 } | |
356 | |
357 return true; | |
358 } | |
359 | |
360 } // namespace fileapi | |
OLD | NEW |