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