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/fileapi/external_mount_points.h" |
| 6 |
| 7 #include "base/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/remote_file_system_proxy.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 FilePath NormalizeFilePath(const FilePath& path) { |
| 23 if (path.empty()) |
| 24 return path; |
| 25 |
| 26 FilePath::StringType path_str = path.StripTrailingSeparators().value(); |
| 27 if (!FilePath::IsSeparator(path_str[path_str.length() - 1])) |
| 28 path_str.append(FILE_PATH_LITERAL("/")); |
| 29 |
| 30 return FilePath(path_str).NormalizePathSeparators(); |
| 31 } |
| 32 |
| 33 // Wrapper around ref-counted ExternalMountPoints that will be used to lazily |
| 34 // create and initialize LazyInstance system ExternalMountPoints. |
| 35 class SystemMountPointsLazyWrapper { |
| 36 public: |
| 37 SystemMountPointsLazyWrapper() |
| 38 : system_mount_points_(fileapi::ExternalMountPoints::CreateRefCounted()) { |
| 39 RegisterDefaultMountPoints(); |
| 40 } |
| 41 |
| 42 ~SystemMountPointsLazyWrapper() {} |
| 43 |
| 44 fileapi::ExternalMountPoints* get() { |
| 45 return system_mount_points_.get(); |
| 46 } |
| 47 |
| 48 private: |
| 49 void RegisterDefaultMountPoints() { |
| 50 #if defined(OS_CHROMEOS) |
| 51 // Add default system mount points. |
| 52 system_mount_points_->RegisterFileSystem( |
| 53 "archive", |
| 54 fileapi::kFileSystemTypeNativeLocal, |
| 55 FilePath(FILE_PATH_LITERAL("/media/archive"))); |
| 56 system_mount_points_->RegisterFileSystem( |
| 57 "removable", |
| 58 fileapi::kFileSystemTypeNativeLocal, |
| 59 FilePath(FILE_PATH_LITERAL("/media/removable"))); |
| 60 system_mount_points_->RegisterFileSystem( |
| 61 "oem", |
| 62 fileapi::kFileSystemTypeRestrictedNativeLocal, |
| 63 FilePath(FILE_PATH_LITERAL("/usr/share/oem"))); |
| 64 |
| 65 // TODO(tbarzic): Move this out of here. |
| 66 FilePath home_path; |
| 67 if (PathService::Get(base::DIR_HOME, &home_path)) { |
| 68 system_mount_points_->RegisterFileSystem( |
| 69 "Downloads", |
| 70 fileapi::kFileSystemTypeNativeLocal, |
| 71 home_path.AppendASCII("Downloads")); |
| 72 } |
| 73 #endif // defined(OS_CHROMEOS) |
| 74 } |
| 75 |
| 76 scoped_refptr<fileapi::ExternalMountPoints> system_mount_points_; |
| 77 }; |
| 78 |
| 79 base::LazyInstance<SystemMountPointsLazyWrapper>::Leaky |
| 80 g_external_mount_points = LAZY_INSTANCE_INITIALIZER; |
| 81 |
| 82 } // namespace |
| 83 |
| 84 namespace fileapi { |
| 85 |
| 86 class ExternalMountPoints::Instance { |
| 87 public: |
| 88 Instance(FileSystemType type, |
| 89 const FilePath& path, |
| 90 RemoteFileSystemProxyInterface* remote_proxy); |
| 91 |
| 92 ~Instance(); |
| 93 |
| 94 FileSystemType type() const { return type_; } |
| 95 const FilePath& path() const { return path_; } |
| 96 RemoteFileSystemProxyInterface* remote_proxy() const { |
| 97 return remote_proxy_.get(); |
| 98 } |
| 99 |
| 100 private: |
| 101 const FileSystemType type_; |
| 102 const FilePath path_; |
| 103 |
| 104 // For file systems that have a remote file system proxy. |
| 105 scoped_refptr<RemoteFileSystemProxyInterface> remote_proxy_; |
| 106 |
| 107 DISALLOW_COPY_AND_ASSIGN(Instance); |
| 108 }; |
| 109 |
| 110 ExternalMountPoints::Instance::Instance(FileSystemType type, |
| 111 const FilePath& path, |
| 112 RemoteFileSystemProxyInterface* proxy) |
| 113 : type_(type), |
| 114 path_(path.StripTrailingSeparators()), |
| 115 remote_proxy_(proxy) { |
| 116 DCHECK(!proxy || (kFileSystemTypeDrive == type_)); |
| 117 } |
| 118 |
| 119 ExternalMountPoints::Instance::~Instance() {} |
| 120 |
| 121 //-------------------------------------------------------------------------- |
| 122 |
| 123 // static |
| 124 ExternalMountPoints* ExternalMountPoints::GetSystemInstance() { |
| 125 return g_external_mount_points.Pointer()->get(); |
| 126 } |
| 127 |
| 128 // static |
| 129 scoped_refptr<ExternalMountPoints> ExternalMountPoints::CreateRefCounted() { |
| 130 return new ExternalMountPoints(); |
| 131 } |
| 132 |
| 133 bool ExternalMountPoints::RegisterFileSystem( |
| 134 const std::string& mount_name, |
| 135 FileSystemType type, |
| 136 const FilePath& path) { |
| 137 return RegisterRemoteFileSystem(mount_name, type, NULL, path); |
| 138 } |
| 139 |
| 140 bool ExternalMountPoints::RegisterRemoteFileSystem( |
| 141 const std::string& mount_name, |
| 142 FileSystemType type, |
| 143 RemoteFileSystemProxyInterface* remote_proxy, |
| 144 const FilePath& path_in) { |
| 145 base::AutoLock locker(lock_); |
| 146 |
| 147 FilePath path = NormalizeFilePath(path_in); |
| 148 if (!ValidateNewMountPoint(mount_name, path)) |
| 149 return false; |
| 150 |
| 151 instance_map_[mount_name] = new Instance(type, path, remote_proxy); |
| 152 if (!path.empty()) |
| 153 path_to_name_map_.insert(std::make_pair(path, mount_name)); |
| 154 return true; |
| 155 } |
| 156 |
| 157 bool ExternalMountPoints::RevokeFileSystem(const std::string& mount_name) { |
| 158 base::AutoLock locker(lock_); |
| 159 NameToInstance::iterator found = instance_map_.find(mount_name); |
| 160 if (found == instance_map_.end()) |
| 161 return false; |
| 162 Instance* instance = found->second; |
| 163 path_to_name_map_.erase(NormalizeFilePath(instance->path())); |
| 164 delete found->second; |
| 165 instance_map_.erase(found); |
| 166 return true; |
| 167 } |
| 168 |
| 169 bool ExternalMountPoints::GetRegisteredPath( |
| 170 const std::string& filesystem_id, FilePath* path) const { |
| 171 DCHECK(path); |
| 172 base::AutoLock locker(lock_); |
| 173 NameToInstance::const_iterator found = instance_map_.find(filesystem_id); |
| 174 if (found == instance_map_.end()) |
| 175 return false; |
| 176 *path = found->second->path(); |
| 177 return true; |
| 178 } |
| 179 |
| 180 bool ExternalMountPoints::CrackVirtualPath(const FilePath& virtual_path, |
| 181 std::string* mount_name, |
| 182 FileSystemType* type, |
| 183 FilePath* path) const { |
| 184 DCHECK(mount_name); |
| 185 DCHECK(path); |
| 186 |
| 187 // The path should not contain any '..' references. |
| 188 if (virtual_path.ReferencesParent()) |
| 189 return false; |
| 190 |
| 191 // The virtual_path should comprise of <mount_name> and <relative_path> parts. |
| 192 std::vector<FilePath::StringType> components; |
| 193 virtual_path.GetComponents(&components); |
| 194 if (components.size() < 1) |
| 195 return false; |
| 196 |
| 197 std::vector<FilePath::StringType>::iterator component_iter = |
| 198 components.begin(); |
| 199 std::string maybe_mount_name = FilePath(*component_iter++).MaybeAsASCII(); |
| 200 if (maybe_mount_name.empty()) |
| 201 return false; |
| 202 |
| 203 FilePath cracked_path; |
| 204 { |
| 205 base::AutoLock locker(lock_); |
| 206 NameToInstance::const_iterator found_instance = |
| 207 instance_map_.find(maybe_mount_name); |
| 208 if (found_instance == instance_map_.end()) |
| 209 return false; |
| 210 |
| 211 *mount_name = maybe_mount_name; |
| 212 const Instance* instance = found_instance->second; |
| 213 if (type) |
| 214 *type = instance->type(); |
| 215 cracked_path = instance->path(); |
| 216 } |
| 217 |
| 218 for (; component_iter != components.end(); ++component_iter) |
| 219 cracked_path = cracked_path.Append(*component_iter); |
| 220 *path = cracked_path; |
| 221 return true; |
| 222 } |
| 223 |
| 224 RemoteFileSystemProxyInterface* ExternalMountPoints::GetRemoteFileSystemProxy( |
| 225 const std::string& mount_name) const { |
| 226 base::AutoLock locker(lock_); |
| 227 NameToInstance::const_iterator found = instance_map_.find(mount_name); |
| 228 if (found == instance_map_.end()) |
| 229 return NULL; |
| 230 return found->second->remote_proxy(); |
| 231 } |
| 232 |
| 233 void ExternalMountPoints::AddMountPointInfosTo( |
| 234 std::vector<MountPointInfo>* mount_points) const { |
| 235 base::AutoLock locker(lock_); |
| 236 DCHECK(mount_points); |
| 237 for (NameToInstance::const_iterator iter = instance_map_.begin(); |
| 238 iter != instance_map_.end(); ++iter) { |
| 239 mount_points->push_back(MountPointInfo(iter->first, iter->second->path())); |
| 240 } |
| 241 } |
| 242 |
| 243 bool ExternalMountPoints::GetVirtualPath(const FilePath& path_in, |
| 244 FilePath* virtual_path) { |
| 245 DCHECK(virtual_path); |
| 246 |
| 247 base::AutoLock locker(lock_); |
| 248 |
| 249 FilePath path = NormalizeFilePath(path_in); |
| 250 std::map<FilePath, std::string>::reverse_iterator iter( |
| 251 path_to_name_map_.upper_bound(path)); |
| 252 if (iter == path_to_name_map_.rend()) |
| 253 return false; |
| 254 |
| 255 *virtual_path = CreateVirtualRootPath(iter->second); |
| 256 if (iter->first == path) |
| 257 return true; |
| 258 return iter->first.AppendRelativePath(path, virtual_path); |
| 259 } |
| 260 |
| 261 FilePath ExternalMountPoints::CreateVirtualRootPath( |
| 262 const std::string& mount_name) const { |
| 263 return FilePath().AppendASCII(mount_name); |
| 264 } |
| 265 |
| 266 ExternalMountPoints::ExternalMountPoints() {} |
| 267 |
| 268 ExternalMountPoints::~ExternalMountPoints() { |
| 269 STLDeleteContainerPairSecondPointers(instance_map_.begin(), |
| 270 instance_map_.end()); |
| 271 } |
| 272 |
| 273 bool ExternalMountPoints::ValidateNewMountPoint(const std::string& mount_name, |
| 274 const FilePath& path) { |
| 275 lock_.AssertAcquired(); |
| 276 |
| 277 // Mount name must not be empty. |
| 278 if (mount_name.empty()) |
| 279 return false; |
| 280 |
| 281 // Verify there is no registered mount point with the same name. |
| 282 NameToInstance::iterator found = instance_map_.find(mount_name); |
| 283 if (found != instance_map_.end()) |
| 284 return false; |
| 285 |
| 286 // Allow empty paths. |
| 287 if (path.empty()) |
| 288 return true; |
| 289 |
| 290 // Verify path is legal. |
| 291 if (path.ReferencesParent() || !path.IsAbsolute()) |
| 292 return false; |
| 293 |
| 294 // Check there the new path does not overlap with one of the existing ones. |
| 295 std::map<FilePath, std::string>::reverse_iterator potential_parent( |
| 296 path_to_name_map_.upper_bound(path)); |
| 297 if (potential_parent != path_to_name_map_.rend()) { |
| 298 if (potential_parent->first == path || |
| 299 potential_parent->first.IsParent(path)) { |
| 300 return false; |
| 301 } |
| 302 } |
| 303 |
| 304 std::map<FilePath, std::string>::iterator potential_child = |
| 305 path_to_name_map_.upper_bound(path); |
| 306 if (potential_child == path_to_name_map_.end()) |
| 307 return true; |
| 308 return !(potential_child->first == path) && |
| 309 !path.IsParent(potential_child->first); |
| 310 } |
| 311 |
| 312 ScopedExternalFileSystem::ScopedExternalFileSystem( |
| 313 const std::string& mount_name, |
| 314 FileSystemType type, |
| 315 const FilePath& path) |
| 316 : mount_name_(mount_name) { |
| 317 ExternalMountPoints::GetSystemInstance()->RegisterFileSystem( |
| 318 mount_name, type, path); |
| 319 } |
| 320 |
| 321 FilePath ScopedExternalFileSystem::GetVirtualRootPath() const { |
| 322 return ExternalMountPoints::GetSystemInstance()-> |
| 323 CreateVirtualRootPath(mount_name_); |
| 324 } |
| 325 |
| 326 ScopedExternalFileSystem::~ScopedExternalFileSystem() { |
| 327 ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(mount_name_); |
| 328 } |
| 329 |
| 330 } // namespace fileapi |
| 331 |
OLD | NEW |