Manager.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2016, ownCloud, Inc.
  5. *
  6. * @author Björn Schießle <bjoern@schiessle.org>
  7. * @author Morris Jobke <hey@morrisjobke.de>
  8. * @author Robin Appelman <robin@icewind.nl>
  9. * @author Robin McCorkell <robin@mccorkell.me.uk>
  10. * @author Roeland Jago Douma <roeland@famdouma.nl>
  11. * @author Jonas <jonas@freesources.org>
  12. *
  13. * @license AGPL-3.0
  14. *
  15. * This code is free software: you can redistribute it and/or modify
  16. * it under the terms of the GNU Affero General Public License, version 3,
  17. * as published by the Free Software Foundation.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU Affero General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU Affero General Public License, version 3,
  25. * along with this program. If not, see <http://www.gnu.org/licenses/>
  26. *
  27. */
  28. namespace OC\Files\Mount;
  29. use OC\Files\Filesystem;
  30. use OC\Files\SetupManager;
  31. use OC\Files\SetupManagerFactory;
  32. use OCP\Cache\CappedMemoryCache;
  33. use OCP\Files\Config\ICachedMountInfo;
  34. use OCP\Files\Mount\IMountManager;
  35. use OCP\Files\Mount\IMountPoint;
  36. use OCP\Files\NotFoundException;
  37. class Manager implements IMountManager {
  38. /** @var MountPoint[] */
  39. private array $mounts = [];
  40. /** @var CappedMemoryCache<IMountPoint> */
  41. private CappedMemoryCache $pathCache;
  42. /** @var CappedMemoryCache<IMountPoint[]> */
  43. private CappedMemoryCache $inPathCache;
  44. private SetupManager $setupManager;
  45. public function __construct(SetupManagerFactory $setupManagerFactory) {
  46. $this->pathCache = new CappedMemoryCache();
  47. $this->inPathCache = new CappedMemoryCache();
  48. $this->setupManager = $setupManagerFactory->create($this);
  49. }
  50. /**
  51. * @param IMountPoint $mount
  52. */
  53. public function addMount(IMountPoint $mount) {
  54. $this->mounts[$mount->getMountPoint()] = $mount;
  55. $this->pathCache->clear();
  56. $this->inPathCache->clear();
  57. }
  58. /**
  59. * @param string $mountPoint
  60. */
  61. public function removeMount(string $mountPoint) {
  62. $mountPoint = Filesystem::normalizePath($mountPoint);
  63. if (\strlen($mountPoint) > 1) {
  64. $mountPoint .= '/';
  65. }
  66. unset($this->mounts[$mountPoint]);
  67. $this->pathCache->clear();
  68. $this->inPathCache->clear();
  69. }
  70. /**
  71. * @param string $mountPoint
  72. * @param string $target
  73. */
  74. public function moveMount(string $mountPoint, string $target) {
  75. $this->mounts[$target] = $this->mounts[$mountPoint];
  76. unset($this->mounts[$mountPoint]);
  77. $this->pathCache->clear();
  78. $this->inPathCache->clear();
  79. }
  80. /**
  81. * Find the mount for $path
  82. *
  83. * @param string $path
  84. * @return IMountPoint
  85. */
  86. public function find(string $path): IMountPoint {
  87. $this->setupManager->setupForPath($path);
  88. $path = Filesystem::normalizePath($path);
  89. if (isset($this->pathCache[$path])) {
  90. return $this->pathCache[$path];
  91. }
  92. if (count($this->mounts) === 0) {
  93. $this->setupManager->setupRoot();
  94. if (count($this->mounts) === 0) {
  95. throw new \Exception("No mounts even after explicitly setting up the root mounts");
  96. }
  97. }
  98. $current = $path;
  99. while (true) {
  100. $mountPoint = $current . '/';
  101. if (isset($this->mounts[$mountPoint])) {
  102. $this->pathCache[$path] = $this->mounts[$mountPoint];
  103. return $this->mounts[$mountPoint];
  104. } elseif ($current === '') {
  105. break;
  106. }
  107. $current = dirname($current);
  108. if ($current === '.' || $current === '/') {
  109. $current = '';
  110. }
  111. }
  112. throw new NotFoundException("No mount for path " . $path . " existing mounts (" . count($this->mounts) ."): " . implode(",", array_keys($this->mounts)));
  113. }
  114. /**
  115. * Find all mounts in $path
  116. *
  117. * @param string $path
  118. * @return IMountPoint[]
  119. */
  120. public function findIn(string $path): array {
  121. $this->setupManager->setupForPath($path, true);
  122. $path = $this->formatPath($path);
  123. if (isset($this->inPathCache[$path])) {
  124. return $this->inPathCache[$path];
  125. }
  126. $result = [];
  127. $pathLength = \strlen($path);
  128. $mountPoints = array_keys($this->mounts);
  129. foreach ($mountPoints as $mountPoint) {
  130. if (substr($mountPoint, 0, $pathLength) === $path && \strlen($mountPoint) > $pathLength) {
  131. $result[] = $this->mounts[$mountPoint];
  132. }
  133. }
  134. $this->inPathCache[$path] = $result;
  135. return $result;
  136. }
  137. public function clear() {
  138. $this->mounts = [];
  139. $this->pathCache->clear();
  140. $this->inPathCache->clear();
  141. }
  142. /**
  143. * Find mounts by storage id
  144. *
  145. * @param string $id
  146. * @return IMountPoint[]
  147. */
  148. public function findByStorageId(string $id): array {
  149. if (\strlen($id) > 64) {
  150. $id = md5($id);
  151. }
  152. $result = [];
  153. foreach ($this->mounts as $mount) {
  154. if ($mount->getStorageId() === $id) {
  155. $result[] = $mount;
  156. }
  157. }
  158. return $result;
  159. }
  160. /**
  161. * @return IMountPoint[]
  162. */
  163. public function getAll(): array {
  164. return $this->mounts;
  165. }
  166. /**
  167. * Find mounts by numeric storage id
  168. *
  169. * @param int $id
  170. * @return IMountPoint[]
  171. */
  172. public function findByNumericId(int $id): array {
  173. $result = [];
  174. foreach ($this->mounts as $mount) {
  175. if ($mount->getNumericStorageId() === $id) {
  176. $result[] = $mount;
  177. }
  178. }
  179. return $result;
  180. }
  181. /**
  182. * @param string $path
  183. * @return string
  184. */
  185. private function formatPath(string $path): string {
  186. $path = Filesystem::normalizePath($path);
  187. if (\strlen($path) > 1) {
  188. $path .= '/';
  189. }
  190. return $path;
  191. }
  192. public function getSetupManager(): SetupManager {
  193. return $this->setupManager;
  194. }
  195. /**
  196. * Return all mounts in a path from a specific mount provider
  197. *
  198. * @param string $path
  199. * @param string[] $mountProviders
  200. * @return MountPoint[]
  201. */
  202. public function getMountsByMountProvider(string $path, array $mountProviders) {
  203. $this->getSetupManager()->setupForProvider($path, $mountProviders);
  204. if (in_array('', $mountProviders)) {
  205. return $this->mounts;
  206. } else {
  207. return array_filter($this->mounts, function ($mount) use ($mountProviders) {
  208. return in_array($mount->getMountProvider(), $mountProviders);
  209. });
  210. }
  211. }
  212. /**
  213. * Return the mount matching a cached mount info (or mount file info)
  214. *
  215. * @param ICachedMountInfo $info
  216. *
  217. * @return IMountPoint|null
  218. */
  219. public function getMountFromMountInfo(ICachedMountInfo $info): ?IMountPoint {
  220. $this->setupManager->setupForPath($info->getMountPoint());
  221. foreach ($this->mounts as $mount) {
  222. if ($mount->getMountPoint() === $info->getMountPoint()) {
  223. return $mount;
  224. }
  225. }
  226. return null;
  227. }
  228. }