external_mount_points.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  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. #include "storage/browser/file_system/external_mount_points.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/files/file_path.h"
  8. #include "base/lazy_instance.h"
  9. #include "build/chromeos_buildflags.h"
  10. #include "storage/browser/file_system/file_system_url.h"
  11. #include "third_party/blink/public/common/storage_key/storage_key.h"
  12. class GURL;
  13. namespace storage {
  14. namespace {
  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. base::FilePath::StringType path_str = path.StripTrailingSeparators().value();
  26. if (!base::FilePath::IsSeparator(path_str.back()))
  27. path_str.append(FILE_PATH_LITERAL("/"));
  28. return base::FilePath(path_str).NormalizePathSeparators();
  29. }
  30. bool IsOverlappingMountPathForbidden(FileSystemType type) {
  31. return type != kFileSystemTypeLocalMedia &&
  32. type != kFileSystemTypeDeviceMedia;
  33. }
  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_(ExternalMountPoints::CreateRefCounted()) {}
  40. ~SystemMountPointsLazyWrapper() = default;
  41. ExternalMountPoints* get() { return system_mount_points_.get(); }
  42. private:
  43. scoped_refptr<ExternalMountPoints> system_mount_points_;
  44. };
  45. base::LazyInstance<SystemMountPointsLazyWrapper>::Leaky
  46. g_external_mount_points = LAZY_INSTANCE_INITIALIZER;
  47. } // namespace
  48. class ExternalMountPoints::Instance {
  49. public:
  50. Instance(FileSystemType type,
  51. const base::FilePath& path,
  52. const FileSystemMountOption& mount_option)
  53. : type_(type),
  54. path_(path.StripTrailingSeparators()),
  55. mount_option_(mount_option) {}
  56. Instance(const Instance&) = delete;
  57. Instance& operator=(const Instance&) = delete;
  58. ~Instance() = default;
  59. FileSystemType type() const { return type_; }
  60. const base::FilePath& path() const { return path_; }
  61. const FileSystemMountOption& mount_option() const { return mount_option_; }
  62. private:
  63. const FileSystemType type_;
  64. const base::FilePath path_;
  65. const FileSystemMountOption mount_option_;
  66. };
  67. //--------------------------------------------------------------------------
  68. // static
  69. ExternalMountPoints* ExternalMountPoints::GetSystemInstance() {
  70. return g_external_mount_points.Pointer()->get();
  71. }
  72. // static
  73. scoped_refptr<ExternalMountPoints> ExternalMountPoints::CreateRefCounted() {
  74. return new ExternalMountPoints();
  75. }
  76. bool ExternalMountPoints::RegisterFileSystem(
  77. const std::string& mount_name,
  78. FileSystemType type,
  79. const FileSystemMountOption& mount_option,
  80. const base::FilePath& path_in) {
  81. base::AutoLock locker(lock_);
  82. base::FilePath path = NormalizeFilePath(path_in);
  83. if (!ValidateNewMountPoint(mount_name, type, path))
  84. return false;
  85. instance_map_[mount_name] =
  86. std::make_unique<Instance>(type, path, mount_option);
  87. if (!path.empty() && IsOverlappingMountPathForbidden(type))
  88. path_to_name_map_.insert(std::make_pair(path, mount_name));
  89. return true;
  90. }
  91. bool ExternalMountPoints::HandlesFileSystemMountType(
  92. FileSystemType type) const {
  93. return type == kFileSystemTypeExternal ||
  94. type == kFileSystemTypeLocalForPlatformApp;
  95. }
  96. bool ExternalMountPoints::RevokeFileSystem(const std::string& mount_name) {
  97. base::AutoLock locker(lock_);
  98. auto found = instance_map_.find(mount_name);
  99. if (found == instance_map_.end())
  100. return false;
  101. Instance* instance = found->second.get();
  102. if (IsOverlappingMountPathForbidden(instance->type()))
  103. path_to_name_map_.erase(NormalizeFilePath(instance->path()));
  104. instance_map_.erase(found);
  105. return true;
  106. }
  107. bool ExternalMountPoints::GetRegisteredPath(const std::string& filesystem_id,
  108. base::FilePath* path) const {
  109. DCHECK(path);
  110. base::AutoLock locker(lock_);
  111. auto found = instance_map_.find(filesystem_id);
  112. if (found == instance_map_.end())
  113. return false;
  114. *path = found->second->path();
  115. return true;
  116. }
  117. bool ExternalMountPoints::CrackVirtualPath(
  118. const base::FilePath& virtual_path,
  119. std::string* mount_name,
  120. FileSystemType* type,
  121. std::string* cracked_id,
  122. base::FilePath* path,
  123. FileSystemMountOption* mount_option) const {
  124. DCHECK(mount_name);
  125. DCHECK(path);
  126. // The path should not contain any '..' references.
  127. if (virtual_path.ReferencesParent())
  128. return false;
  129. // The virtual_path should comprise of <mount_name> and <relative_path> parts.
  130. std::vector<base::FilePath::StringType> components =
  131. virtual_path.GetComponents();
  132. if (components.size() < 1)
  133. return false;
  134. auto component_iter = components.begin();
  135. std::string maybe_mount_name =
  136. base::FilePath(*component_iter++).AsUTF8Unsafe();
  137. base::FilePath cracked_path;
  138. {
  139. base::AutoLock locker(lock_);
  140. auto found_instance = instance_map_.find(maybe_mount_name);
  141. if (found_instance == instance_map_.end())
  142. return false;
  143. *mount_name = maybe_mount_name;
  144. const Instance* instance = found_instance->second.get();
  145. if (type)
  146. *type = instance->type();
  147. cracked_path = instance->path();
  148. *mount_option = instance->mount_option();
  149. }
  150. for (; component_iter != components.end(); ++component_iter)
  151. cracked_path = cracked_path.Append(*component_iter);
  152. *path = cracked_path;
  153. return true;
  154. }
  155. FileSystemURL ExternalMountPoints::CrackURL(
  156. const GURL& url,
  157. const blink::StorageKey& storage_key) const {
  158. FileSystemURL filesystem_url = FileSystemURL(url, storage_key);
  159. if (!filesystem_url.is_valid())
  160. return FileSystemURL();
  161. return CrackFileSystemURL(filesystem_url);
  162. }
  163. FileSystemURL ExternalMountPoints::CreateCrackedFileSystemURL(
  164. const blink::StorageKey& storage_key,
  165. FileSystemType type,
  166. const base::FilePath& virtual_path) const {
  167. return CrackFileSystemURL(FileSystemURL(storage_key, type, virtual_path));
  168. }
  169. void ExternalMountPoints::AddMountPointInfosTo(
  170. std::vector<MountPointInfo>* mount_points) const {
  171. base::AutoLock locker(lock_);
  172. DCHECK(mount_points);
  173. for (const auto& pair : instance_map_) {
  174. mount_points->push_back(MountPointInfo(pair.first, pair.second->path()));
  175. }
  176. }
  177. bool ExternalMountPoints::GetVirtualPath(const base::FilePath& path_in,
  178. base::FilePath* virtual_path) const {
  179. DCHECK(virtual_path);
  180. base::AutoLock locker(lock_);
  181. base::FilePath path = NormalizeFilePath(path_in);
  182. std::map<base::FilePath, std::string>::const_reverse_iterator iter(
  183. path_to_name_map_.upper_bound(path));
  184. if (iter == path_to_name_map_.rend())
  185. return false;
  186. *virtual_path = CreateVirtualRootPath(iter->second);
  187. if (iter->first == path)
  188. return true;
  189. return iter->first.AppendRelativePath(path, virtual_path);
  190. }
  191. base::FilePath ExternalMountPoints::CreateVirtualRootPath(
  192. const std::string& mount_name) const {
  193. return base::FilePath().Append(base::FilePath::FromUTF8Unsafe(mount_name));
  194. }
  195. FileSystemURL ExternalMountPoints::CreateExternalFileSystemURL(
  196. const blink::StorageKey& storage_key,
  197. const std::string& mount_name,
  198. const base::FilePath& path) const {
  199. return CreateCrackedFileSystemURL(
  200. storage_key, kFileSystemTypeExternal,
  201. // Avoid using FilePath::Append as path may be an absolute path.
  202. base::FilePath(CreateVirtualRootPath(mount_name).value() +
  203. base::FilePath::kSeparators[0] + path.value()));
  204. }
  205. void ExternalMountPoints::RevokeAllFileSystems() {
  206. NameToInstance instance_map_copy;
  207. {
  208. base::AutoLock locker(lock_);
  209. // This swap moves the contents of instance_map_ to the local variable so
  210. // they can be freed outside the lock.
  211. instance_map_copy.swap(instance_map_);
  212. path_to_name_map_.clear();
  213. }
  214. }
  215. ExternalMountPoints::ExternalMountPoints() = default;
  216. ExternalMountPoints::~ExternalMountPoints() = default;
  217. FileSystemURL ExternalMountPoints::CrackFileSystemURL(
  218. const FileSystemURL& url) const {
  219. if (!HandlesFileSystemMountType(url.type()))
  220. return FileSystemURL();
  221. base::FilePath virtual_path = url.path();
  222. if (url.type() == kFileSystemTypeLocalForPlatformApp) {
  223. #if BUILDFLAG(IS_CHROMEOS_ASH)
  224. // On Chrome OS, find a mount point and virtual path for the external fs.
  225. if (!GetVirtualPath(url.path(), &virtual_path))
  226. return FileSystemURL();
  227. #else
  228. // On other OS, it is simply a native local path.
  229. return FileSystemURL(url.storage_key(), url.mount_type(),
  230. url.virtual_path(), url.mount_filesystem_id(),
  231. kFileSystemTypeLocal, url.path(), url.filesystem_id(),
  232. url.mount_option());
  233. #endif
  234. }
  235. std::string mount_name;
  236. FileSystemType cracked_type;
  237. std::string cracked_id;
  238. base::FilePath cracked_path;
  239. FileSystemMountOption cracked_mount_option;
  240. if (!CrackVirtualPath(virtual_path, &mount_name, &cracked_type, &cracked_id,
  241. &cracked_path, &cracked_mount_option)) {
  242. return FileSystemURL();
  243. }
  244. return FileSystemURL(
  245. url.storage_key(), url.mount_type(), url.virtual_path(),
  246. !url.filesystem_id().empty() ? url.filesystem_id() : mount_name,
  247. cracked_type, cracked_path, cracked_id.empty() ? mount_name : cracked_id,
  248. cracked_mount_option);
  249. }
  250. bool ExternalMountPoints::ValidateNewMountPoint(const std::string& mount_name,
  251. FileSystemType type,
  252. const base::FilePath& path) {
  253. lock_.AssertAcquired();
  254. // Mount name must not be empty.
  255. if (mount_name.empty())
  256. return false;
  257. // Verify there is no registered mount point with the same name.
  258. auto found = instance_map_.find(mount_name);
  259. if (found != instance_map_.end())
  260. return false;
  261. // Allow empty paths.
  262. if (path.empty())
  263. return true;
  264. // Verify path is legal.
  265. if (path.ReferencesParent() || !path.IsAbsolute())
  266. return false;
  267. if (IsOverlappingMountPathForbidden(type)) {
  268. // Check there the new path does not overlap with one of the existing ones.
  269. std::map<base::FilePath, std::string>::reverse_iterator potential_parent(
  270. path_to_name_map_.upper_bound(path));
  271. if (potential_parent != path_to_name_map_.rend()) {
  272. if (potential_parent->first == path ||
  273. potential_parent->first.IsParent(path)) {
  274. return false;
  275. }
  276. }
  277. auto potential_child = path_to_name_map_.upper_bound(path);
  278. if (potential_child != path_to_name_map_.end()) {
  279. if (potential_child->first == path ||
  280. path.IsParent(potential_child->first)) {
  281. return false;
  282. }
  283. }
  284. }
  285. return true;
  286. }
  287. } // namespace storage